Hey all, I am relatively new to PowerShell and am trying to learn to use functions. What confuses me is variable scope. My brain constantly wrestles with the question of where to place variables. The same issue pops up with Scriptblocks as well to be honest. I’ve read the MS documentation regarding scopes but it’s still not ringing any bells for me. I also never see their examples in other peoples’ scripts (e.x. $script:variable
). I am hoping someone can take my very incorrect code below and give me some real-world examples of how to properly do this. Here is my code (it’s for obtaining the Installation ID of Windows 7 and Server 2008 machines in a offline environment for Microsoft’s Extended Support activation):
function Get-InstallationID {
[cmdletbinding()]
param (
[string]$ComputerName = (Get-ADComputer -Filter { OperatingSystem -Like ‘Windows 7’ -or OperatingSystem -Like ‘Server 2008’ } -Properties OperatingSystem | Select-Object -ExpandProperty Name),
[string]$ProductKey = ‘22VMR-WVR6H-2H4CX-G2Y9M-R9RFW’, #This changes each year.
[string]$ActivationID = ‘553673ed-6ddf-419c-a153-b760283472fd’ #This changes each year.
)
#---------------------------------------------------------------------------------Install ESU Product Key if Not Already Installed---------------------------------------------------------------------------------
#Get current year.
$Year = (Get-Date -Format ‘yyyy’)
#Location of the ‘LicenseInfo.txt’.
$licenseinfo = “C:\LicenseInfo_$Year.txt”
#If ‘LicenseInfo.txt’ already exists, write to console’
if (-not(Test-Path -Path $licenseinfo)) {
try {
Invoke-Command -ComputerName $PC -ScriptBlock {
# NOTE: This Product Key needs to be updated each year & will be provided by the Infrastructure team.
cscript.exe C:\Windows\System32\slmgr.vbs /ipk $ProductKey
# NOTE: This Activation ID needs to be updated each year: [ARCHIVED] How to get Extended Security Updates for eligible Windows devices - Microsoft Tech Community
cscript.exe C:\Windows\System32\slmgr.vbs /dlv $ActivationID > $licenseinfo }
}
catch {
$PSItem.Exception.Message | Tee-Object -FilePath $Log -Append
Write-Output “$licenseinfo could not be generated on $env:COMPUTERNAME.”
break
}
#---------------------------------------------------------------------------------Generate Installation ID and Output to File---------------------------------------------------------------------------------
#Additional check to make sure the correct product is being activated.
$PartialProductKey = (Get-Content $licenseinfo -TotalCount 19 | Select-String -Pattern (“Partial Product Key”)).ToString()
#Remove the first 21 characters, leaving only the actual PartialProductKey.
$PartialProductKey = $PartialProductKey.substring(21)
#This checks the ‘Partial Product Key:’ line of C:\LicenseInfo.txt to ensure the ‘ESU-Year1’ product is listed first since the InstallationID gets pulled from the first product.
if ($PartialProductKey -ne $ProductKey.Substring(24)) {
Write-Output “Partial Product Key does not = $($ProductKey.Substring(24)) on $PC. Check C:\LicenseInfo.txt on that machine and ensure ‘ESU-Year1’ product is listed first!”
}
else {
#Pull the Installation ID from ‘LicenseInfo.txt’ and output to $outfile.
$InstallationID = Get-Content $licenseinfo -TotalCount 19 | Select-String -Pattern (“Installation ID”) | ForEach-Object { $_.line }
#Create a custom object so we can output data to Excel in organized columns.
$CSVobject = [PSCustomObject]@{
Hostname = $env:COMPUTERNAME
InstallationID = $InstallationID
ConfirmationID = ‘’
}
$CSVobject | Export-Csv -NoTypeInformation -Path $Using:Outfile -Force
}
}
}
#---------------------------------------------------------------------------------Install ESU Product Key if Not Already Installed---------------------------------------------------------------------------------
$Outfile = “C:\Users$env:USERNAME\Desktop\InstallationIDs.csv”
$Log = “C:\Windows\appslogs\ESU_Activation_$(Get-Date -Format yyyyMMdd_HHmmss).txt”
$OnlinePCs = [System.Collections.ArrayList]::new()
foreach ($PC in $ComputerName) {
if (Test-NetConnection -ComputerName $PC -Port 5985 -InformationLevel Quiet) {
[void]$online.Add(“$PC”)
}
else {
Write-Output “$PC could not be contacted on port 5985. Try pinging it.” | Tee-Object -FilePath $Log -Append
}
}
try {
Invoke-Command -ComputerName $OnlinePCs -ScriptBlock ${function:Get-InstallationID} -ErrorAction Stop
Write-Output “Successfully pulled Installation ID from $PC”
}
catch{
$PSItem.Exception.Message | Tee-Object -FilePath $Log -Append
Write-Output “Something went wrong - check error message\log.” | Tee-Object -FilePath $Log -Append
}
finally{
$Error.Clear()
}
My 3 main concerns are the following variables $CSVobject, $Outfile, and $Log. I have a feeling all 3 are wrong. Not sure how the data obtained within the function is passed back to the PC running the script, essentially. Thanks in advance for any and all help!