Issue with installing a Windows feature on multiple servers

Hi,

Have a script I’ve been working on to automate the deployment of FSRM to block crypto filenames have it working when targeting single servers but tried to expand it to include multiple servers and hitting an issue with the install of “fs-resource-manager”.

What seems to happen is the script picks up the first server name of the $Servers variable installs the role fine but then doesnt install it on the 2nd server.

The script then tries to configure FSRM on the 1st and 2nd servers and errors because the role hasnt been installed on the second server but works OK on the 1st.

Any idea where I’m going wrong?

[CmdletBinding()]
param(
    [string[]]$Server
)
#Define Global Variables
$global:Ver = (Get-CimInstance -ComputerName $Ser win32_OperatingSystem).Version
$global:serv = $Server

foreach ($Ser in $Server) {
    # Check for Windows 2012 
    if ($ver -eq '6.2') {
        $OSCheck = $true
        Write-Host " "
        Write-Host "The server $Ser is running Windows Server 2012"
        Write-Host " "
    }
    # Check for Windows 2012 R2
    if ($ver -eq '6.3') {
        $OSCheck = $true
        Write-Host " "
        Write-Host "The server $Ser is running Windows Server 2012 R2"
        Write-Host " "
    }
    # Check for Windows 2016
    if ($ver -eq '10.0') {
        $OSCheck = $true
        Write-Host " "
        Write-Host "The server $Ser is running Windows Server 2016"
        Write-Host " "
    }
    #Check for Windows 2019
    if ($ver -eq '10.0.17763') {
        $OSCheck = $true
        Write-Host " "
        Write-Host "The server $Ser is running Windows Server 2019"
        Write-Host " "
    }

    # If Windows 2012, 2012 R2, 2016 or 2019 are not found, exit with error
    if ($OSCheck -ne $true) {
        Write-Host " "
        Write-Error "The server $Ser is not running a supported version of Windows Server. Exiting the script." 
        Write-Host " "
        ThrowError
    }
}

# Function - Check FSRM Installed
function Check-FSRM {
    foreach ($Ser in $Server) {
        # Formatting
        Write-Host " "
        Write-Host " "

        $checkFSRM = Get-WindowsFeature -ComputerName $Ser -Name FS-Resource-Manager

        if ($checkFSRM.Installed -ne $true) {
            Write-Host "FSRM is not " -nonewline -ForegroundColor White
            Write-Host "installed on $ser." -ForegroundColor Red -nonewline
            Write-Host " "
            Install-FSRM
        }
        else {
            Write-Host "FSRM is already " -nonewline -ForegroundColor White
            Write-Host "installed on $ser" -ForegroundColor Green -nonewline
            Write-Host "Continuing to configure FSRM..." -ForegroundColor White -NoNewline
            Configure-FSRM
        }

    }
}
# end Check-FSRM

function Install-FSRM {
    #Formatting
    Write-Host " "
    Write-Host " "
    #Install on Windows 2012, 2012 R2 or 2016 
    foreach ($Ser in $Server) {
        Install-WindowsFeature fs-resource-manager -ComputerName $Ser -IncludeManagementTools 
        Write-Host " "
        Write-Host "Rebooting $Ser to enable FSRM PowerShell Modules...."
        Restart-Computer -ComputerName $Ser -Force -Wait -For PowerShell
        Configure-FSRM

    }
}

#endregion Install-FSRM

function Configure-FSRM {
    #Configure FSRM
    foreach ($ser in $Server) {
        Invoke-Command -ComputerName $Ser -ScriptBlock {
            #Create File Group for FSRM
            New-FsrmFileGroup -name "Ransomware Files" -IncludePattern @((Invoke-WebRequest -Uri "https://fsrm.experiant.ca/api/v1/combined" -UseBasicParsing).content | convertfrom-json | ForEach-Object { $_.filters })
            #Create FSRM Template xml file and import template then remove xml file once imported
            $FSRMTemplate = @"
<?xml version="1.0" ?><Root ><Header DatabaseVersion = '2.0' ></Header><QuotaTemplates ></QuotaTemplates><DatascreenTemplates ><DatascreenTemplate Name = 'RansomwareCheck' Id = '{122F5AB4-9DF0-4F09-B89E-0F7BDC9D46CC}' Flags = '1' Description = '' ><BlockedGroups ><FileGroup FileGroupId = '{FCD4D266-025D-4CEC-BCF5-BBFA939DF1A1}' Name = 'Ransomware%sFiles' ></FileGroup></BlockedGroups><FileGroupActions ><Action Type="1" Id="{73AFB339-FF17-42DC-B9B9-E7C9A8E7C9A9}" EventType="2" MessageText="User%s[Source%sIo%sOwner]%sattempted%sto%ssave%s[Source%sFile%sPath]%sto%s[File%sScreen%sPath]%son%sthe%s[Server]%sserver.%sThis%sfile%sis%sin%sthe%s[Violated%sFile%sGroup]%sfile%sgroup,%swhich%sis%snot%spermitted%son%sthe%sserver." /><Action Type="3" Id="{D0B80CC5-E6DD-481C-9534-19944A851A72}" ExecutablePath="C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" Arguments=""C:\Scripts\ScriptToDenyPermissions.PS1"" WorkingDirectory="C:\Windows\System32\WindowsPowerShell\v1.0\" Account="3" MonitorCommand="0" KillTimeOut="0" LogResult="1" CurrentSid="S-1-5-21-220523388-1078081533-839522115-4200" /><Action Type="2" Id="{5F8A5821-5271-429D-A9BC-AFADC0C621EF}" MailFrom="" MailReplyTo="" MailTo="[Admin%sEmail]" MailCc="" MailBcc="" MailSubject="Unauthorized%sfile%sfrom%sthe%s[Violated%sFile%sGroup]%sfile%sgroup%sdetected" MessageText="User%s[Source%sIo%sOwner]%sattempted%sto%ssave%s[Source%sFile%sPath]%sto%s[File%sScreen%sPath]%son%sthe%s[Server]%sserver.%s%r%n%r%nThis%sfile%sis%sin%sthe%s[Violated%sFile%sGroup]%sfile%sgroup,%swhich%sis%snot%spermitted%son%sthe%sserver.%r%n%r%nImmediately%stake%sthe%suser&apos;s%scomputer%soff%sthe%snetwork%sand%scheck%sfor%sinfections.%s%sMay%sbe%sworth%sreinstalling%sthe%sOS,%sto%sbe%scertain." /></FileGroupActions></DatascreenTemplate></DatascreenTemplates><FileGroups ></FileGroups></Root>
"@
            $FSRMTemplate | Out-File -FilePath C:\users\public\FSRMTemplate.xml

            Filescrn template import /file:C:\users\public\FSRMTemplate.xml | Out-Null

            Remove-Item -path C:\Users\Public\FSRMTemplate.xml
            #find all drives that are not the C drive and create file screen for those drives. Essentially all drives except the C drive will be monitored for crypto locker files.
            $disks = GET-WMIOBJECT win32_logicaldisk -filter "DriveType='3'" | Where-Object { $_.deviceid -ne "C:" }
            ForEach ($disk in $disks) {
                $DRIVE = $DISK.DeviceID
                New-FSRMFILEScreen -path $DRIVE -template "RansomwareCheck"
            }
            #Define Powershell update script
            $psupdate = @"
Set-FsrmFileGroup -name "Ransomware Files" -IncludePattern @((Invoke-WebRequest -Uri "https://fsrm.experiant.ca/api/v1/combined" -UseBasicParsing).content | convertfrom-json | ForEach-Object {$_.filters})
"@
            if (!(Test-path -path "C:\Scripts")) {
                New-item -ItemType Directory -path "C:\Scripts" | Out-Null
            }
            $psupdate | Out-File -FilePath "C:\Scripts\Update-FSRMRansomware.ps1"

            #Define Scheduled Task
            $Action = New-ScheduledTaskAction -execute "PowerShell.exe" -Argument "-ExecutionPolicy Bypass C:\Scripts\Update-FSRMRansomware.ps1"
            $Trigger = New-ScheduledTaskTrigger -Daily -At '12AM'
            $msg = "Enter the username and password that will run the Scheduled Task";
            $credential = $Host.UI.PromptForCredential("Task Username and password", $msg, "$env:USERDOMAIN\$env:USERNAME", $env:USERDOMAIN)
            $username = $credential.Username
            $password = $credential.GetNetworkCredential().password
            Register-ScheduledTask -TaskName "Update-FSRMRansomware" -Description "Scheduled Task to update FSRM file lists from web." -Trigger $Trigger -User $username -Password $password -Action $Action -RunLevel Highest
            #endregion Configure FSRM
        }
    }
}

Check-FSRM