Public/Copy-WmiNamespace.ps1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#region Function Copy-WmiNamespace
Function Copy-WmiNamespace {
<#
.SYNOPSIS
    This function is used to copy a WMI namespace.
.DESCRIPTION
    This function is used to copy a WMI namespace to another namespace. .
.PARAMETER NamespaceSource
    Specifies the source namespace to copy.
.PARAMETER NamespaceDestination
    Specifies the destination namespace.
.PARAMETER Force
    This switch is used to overwrite the destination namespace.
.EXAMPLE
    Copy-WmiNamespace -NamespaceSource 'ROOT\SCCMZone' -NamespaceDestination 'ROOT\cimv2' -Force
.EXAMPLE
    Copy-WmiNamespace -NamespaceSource 'ROOT\SCCMZone' -NamespaceDestination 'ROOT\cimv2' -ErrorAction 'SilentlyContinue'
.NOTES
    This is a module function and can typically be called directly.
.LINK
    https://sccm-zone.com
.LINK
    https://github.com/JhonnyTerminus/SCCM
#>

    [CmdletBinding()]
    Param (
        [Parameter(Mandatory=$true,Position=0)]
        [ValidateNotNullorEmpty()]
        [string]$NamespaceSource,
        [Parameter(Mandatory=$true,Position=1)]
        [ValidateNotNullorEmpty()]
        [string]$NamespaceDestination,
        [Parameter(Mandatory=$false,Position=3)]
        [ValidateNotNullorEmpty()]
        [switch]$Force = $false
    )

    Begin {
        ## Get the name of this function and write header
        [string]${CmdletName} = $PSCmdlet.MyInvocation.MyCommand.Name
        Write-FunctionHeaderOrFooter -CmdletName ${CmdletName} -CmdletBoundParameters $PSBoundParameters -Header
    }
    Process {
        Try {

            ## Check if the source namespace exists
            $null = Get-WmiNamespace -Namespace $NamespaceSource -ErrorAction 'Stop'

            ## Get source namespace tree
            $NamespaceSourceTree = Get-WmiNamespace -Namespace $NamespaceSource -Recurse -ErrorAction 'SilentlyContinue'

            ## Check if we need to copy root namespace classes
            $ClassNameSourceRoot = Get-WmiClass -Namespace $NamespaceSource -ErrorAction 'SilentlyContinue'

            # Copy root namespace classes if present
            If ($ClassNameSourceRoot) {
                # Copy classes one by one
                $ClassNameSourceRoot | ForEach-Object {
                    Copy-WmiClass -NamespaceSource $NamespaceSource -NamespaceDestination $NamespaceDestination -ClassName $_.CimClassName -CreateDestination -Force -ErrorAction 'Stop'
                }
            }

            ## Parse namespace tree and copy namespaces and classes one by one
            $NamespaceSourceTree | ForEach-Object {

                # Initialize the $ShouldCopy variable with $true
                [boolean]$ShouldCopy = $true

                # Set current namespace source and destination paths. The destination is set by replacing the source namespace with the destination namespace.
                [string]$NamespaceSourcePath = $_.FullName
                [string]$NamespaceDestinationPath = $NamespaceSourcePath -ireplace [regex]::Escape($NamespaceSource), $NamespaceDestination

                # Check if the destination namespace exists
                $NamespaceDestinationTest = Get-WmiNamespace -Namespace $NamespaceDestinationPath -ErrorAction 'SilentlyContinue'

                # If the namespace already exists in the destination and the -Force switch is specified remove the namespace, otherwise set the $ShouldCopy variable to $false
                If ($NamespaceDestinationTest -and $Force) {
                    $null = Remove-WmiNamespace -Namespace  $NamespaceDestinationPath -Force
                }
                ElseIf ($NamespaceDestinationTest) {
                    $ShouldCopy = $false
                }

                # Copy the namespace if the $ShouldCopy variable is set to $true
                If ($ShouldCopy) {

                    # Create the destination namespace
                    $CopyNamespace = New-WmiNamespace -Namespace $NamespaceDestinationPath -CreateSubTree -ErrorAction 'Stop'

                    # Get current source namespace classes
                    $ClassNameSource = Get-WmiClass -Namespace $NamespaceSourcePath -ErrorAction 'SilentlyContinue'

                    # Copy classes if present in the current source namespace
                    If ($ClassNameSource) {
                        # Copy classes one by one
                        $ClassNameSource | ForEach-Object {
                            Copy-WmiClass -NamespaceSource $NamespaceSourcePath -NamespaceDestination $NamespaceDestinationPath -ClassName $_.CimClassName -Force -ErrorAction 'Stop'
                        }
                    }
                }
                Else {

                    ## If a destination namespace is already present log error and stop execution if -ErrorAction 'Stop' is specified
                    $DestinationNamespaceExistsErr = "Destination namespace [$NamespaceDestinationPath] already exists. Use the -Force switch to overwrite."
                    Write-Log -Message $DestinationNamespaceExistsErr -Severity 2 -Source ${CmdletName}
                    Write-Error -Message $NamespaceAlreadyExistsErr -Category 'ResourceExists'
                }
            }
        }
        Catch {
            Write-Log -Message "Failed to copy namespace. `n$(Resolve-Error)" -Severity 3 -Source ${CmdletName}
            Break
        }
        Finally {
            Write-Output -InputObject $CopyNamespace
        }
    }
    End {
        Write-FunctionHeaderOrFooter -CmdletName ${CmdletName} -Footer
    }
}
#endregion