Param (
    [parameter(Mandatory=$true)][string] $user,
    [bool] $allowInherit = $false,
    [bool] $deny = $false,
    [switch]$Force,
    [System.Management.Automation.PSCredential] $credential = $null,
    [switch]$Version
)

# -----------------------------------------
# Run once guard
# -----------------------------------------
$Vendor = "Shinken"
$ScriptName = "WMICIMConfig"
$RegPath = "HKLM:\SOFTWARE\$Vendor\$ScriptName"
$FlagName = "Completed"
$SCRIPT_VERSION = "V02.00.00-RC000.11"

if ($Version) {
    Write-Host "Version : $SCRIPT_VERSION" -ForegroundColor Gray
    exit 0
}

if (-not $Force) {
    if (Test-Path "$RegPath") {
        $Flag = (Get-ItemProperty -Path $RegPath -Name $FlagName -ErrorAction SilentlyContinue).$FlagName
        if ($Flag -eq 1) {
            Write-Host "Script has already run once. Aborting.."
            Write-Host "Use -Force to run it anyway."
            exit 0
        }
    }
}

if (-not (Test-Path $RegPath)) { New-Item -Path $RegPath -Force | Out-Null }
New-ItemProperty -Path $RegPath -Name $FlagName -Value 1 -PropertyType DWord -Force | Out-Null

# -----------------------------------------
# The scripts starts here
# -----------------------------------------
 
$namespaces = @("root\cimv2", "root\standardcimv2")
$permissions = @("Enable", "RemoteAccess")
 
foreach ($namespace in $namespaces) {
    Write-Host "Configuration des permissions pour le namespace: $namespace"
    $ErrorActionPreference = "Stop"
     
    Function Get-AccessMaskFromPermission($permissions) {
        $WBEM_ENABLE = 1
        $WBEM_METHOD_EXECUTE = 2
        $WBEM_FULL_WRITE_REP = 4
        $WBEM_PARTIAL_WRITE_REP = 8
        $WBEM_WRITE_PROVIDER = 0x10
        $WBEM_REMOTE_ACCESS = 0x20
        $READ_CONTROL = 0x20000
        $WRITE_DAC = 0x40000
 
        $WBEM_RIGHTS_FLAGS = $WBEM_ENABLE,$WBEM_METHOD_EXECUTE,$WBEM_FULL_WRITE_REP,`
            $WBEM_PARTIAL_WRITE_REP,$WBEM_WRITE_PROVIDER,$WBEM_REMOTE_ACCESS,`
            $READ_CONTROL,$WRITE_DAC
 
        $WBEM_RIGHTS_STRINGS = "Enable","MethodExecute","FullWrite","PartialWrite",`
            "ProviderWrite","RemoteAccess","ReadSecurity","WriteSecurity"
 
        $permissionTable = @{}
        for ($i = 0; $i -lt $WBEM_RIGHTS_FLAGS.Length; $i++) {
            $permissionTable.Add($WBEM_RIGHTS_STRINGS[$i].ToLower(), $WBEM_RIGHTS_FLAGS[$i])
        }
 
        $accessMask = 0
        foreach ($permission in $permissions) {
            if (-not $permissionTable.ContainsKey($permission.ToLower())) {
                throw "Unknown permission: $permission`nValid permissions: $($permissionTable.Keys)"
            }
            $accessMask += $permissionTable[$permission.ToLower()]
        }
        $accessMask
    }

    if ($PSBoundParameters.ContainsKey("Credential")) {
        $remoteparams = @{ComputerName=$computerName;Credential=$credential}
    } else {
        $remoteparams = @{}
    }

    $invokeparams = @{Namespace=$namespace;Path="__systemsecurity=@"} + $remoteParams  
    $output = Invoke-WmiMethod @invokeparams -Name GetSecurityDescriptor
    if ($output.ReturnValue -ne 0) {
        throw "GetSecurityDescriptor failed: $($output.ReturnValue)"
    }
 
    $acl = $output.Descriptor
    $OBJECT_INHERIT_ACE_FLAG = 0x1
    $CONTAINER_INHERIT_ACE_FLAG = 0x2
 
    $computerName = (Get-WmiObject @remoteparams Win32_ComputerSystem).Name
 
    if ($user.Contains('\')) {
        $domainaccount = $user.Split('\')
        $domain = $domainaccount[0]
        if (($domain -eq ".") -or ($domain -eq "BUILTIN")) {
            $domain = $computerName
        }
        $accountname = $domainaccount[1]
    } elseif ($user.Contains('@')) {
        $domainaccount = $user.Split('@')
        $domain = $domainaccount[1].Split('.')[0]
        $accountname = $domainaccount[0]
    } else {
        $domain = $computerName
        $accountname = $user
    }
 
    $getparams = @{Class="Win32_Account";Filter="Domain='$domain' and Name='$accountname'"} + $remoteParams
    $win32account = Get-WmiObject @getparams
    if ($win32account -eq $null) {
        throw "User / Group was not found: $user"
    }
 
    $accessMask = Get-AccessMaskFromPermission($permissions)
    $ace = (New-Object System.Management.ManagementClass("win32_Ace")).CreateInstance()
            $ace.AccessMask = $accessMask
 
            if ($allowInherit) {
                $ace.AceFlags = $OBJECT_INHERIT_ACE_FLAG + $CONTAINER_INHERIT_ACE_FLAG
            } else {
                $ace.AceFlags = 0
            }
 
            $trustee = (New-Object System.Management.ManagementClass("win32_Trustee")).CreateInstance()
            $trustee.SidString = $win32account.Sid
            $ace.Trustee = $trustee
 
            $ACCESS_ALLOWED_ACE_TYPE = 0x0
            $ACCESS_DENIED_ACE_TYPE = 0x1
 
            if ($deny) {
                $ace.AceType = $ACCESS_DENIED_ACE_TYPE
            } else {
                $ace.AceType = $ACCESS_ALLOWED_ACE_TYPE
            }
            $acl.DACL += $ace.psobject.immediateBaseObject
 
    $setparams = @{Name="SetSecurityDescriptor";ArgumentList=$acl.psobject.immediateBaseObject} + $invokeParams
    $output = Invoke-WmiMethod @setparams
    if ($output.ReturnValue -ne 0) {
        throw "SetSecurityDescriptor failed: $($output.ReturnValue)"
    }
     
    Write-Host "Permissions configurées avec succès pour $user sur $namespace"
}
 
Write-Host "Configuration terminée pour tous les namespaces"

Write-Host "Redémarrage de WMI ..."
Restart-Service Winmgmt -Force
Write-Host "Redémarrage de WMI : OK"

Write-Host "Redémarrage de WinRM ..."
Restart-Service WinRM -Force
Write-Host "Redémarrage de WinRM : OK"
