I have written a PowerShell script, an application that allow PC Refresh to set Company, DepartmentNumber, etc. on an AD object. In development everthing works fine. Obviously I have AD installed on my machine. I have compiled my app to a .exe and placed it on a network share where the techs will execute it from there as they start up a new computer or refresh from Windows 7 to Windows 10 mostly.
The problem is the new PC will not have Active Directory installed at this point in time. I need to find a way to have my app intall, import and run Active Directory as on start up of new or refreshed computers. How do I accomplish this?
Below is some relevant code I use to import the module if it exist on the machine.
$RestoreForm_Load = {
# Load the ActiveDirectory module if it's available
# Check if the ActiveDirectory module is installed
if ((Get-Module -ListAvailable | where { $_.Name -eq 'ActiveDirectory' }) -eq $null) {
$labelDialogRedRestore.Text += "You need to install the ActiveDirectory module!`n"
} else {
# Check if the ActiveDirectory module is allready Imported
if ((Get-Module ActiveDirectory) -eq $null) {
Import-Module ActiveDirectory -ErrorAction 'SilentlyContinue'
$labelDialogGreenRestore.Text += "ActiveDirectory module imported`n"
} else {
$labelDialogGreenRestore.Text += "ActiveDirectory allready imported`n"
}
}
Only the Windows Server versions have the AD module, or any other part of the RSAT (Remote Server Administration Tools) for that matter, available for installation out of the box. You can use Add-WindowsFeature (or Install-WindowsFeature, which replaced the former in Windows 2012 and newer) to install the module on a server:
Import-Module ServerManager
$os = (Get-WmiObject Win32_OperatingSystem).Caption
switch -wildcard ($os) {
'Windwos Server 2008*' {
Add-WindowsFeature RSAT-AD-PowerShell -IncludeAllSubFeatures
}
'Windows Server 2012*' {
Install-WindowsFeature RSAT-AD-PowerShell -IncludeAllSubFeatures
}
}
Windows client versions don't come with the RSAT. You need to install the correct RSAT package first before you can install the AD PowerShell cmdlets. The link list in the KB article is a little outdated, though. The link for the Windows 10 Preview RSAT package doesn't work anymore. Here is the download link for the release version.
Once you have installed the update on the clients, you can install the module for instance via dism:
dism /Online /Enable-Feature /FeatureName:RemoteServerAdministrationTools-Roles-AD-Powershell
Note that (at least on the client versions) the feature name may differ between versions (the feature is named RemoteServerAdministrationTools-Roles-AD-Powershell in the Windows 7 RSAT, but RSATClient-Roles-AD-Powershell in the Windows 10 RSAT), so you may need to use a switch statement on the clients as well:
$os = (Get-WmiObject Win32_OperatingSystem).Caption
$name = switch -wildcard ($os) {
'Windows 7*' { 'RemoteServerAdministrationTools-Roles-AD-Powershell' }
'Windows 8*' { '???' }
'Windows 10*' { 'RSATClient-Roles-AD-Powershell' }
}
& dism /Online /Enable-Feature /FeatureName:$name
Also, beware that regardless of which system you're installing the module on (server or client) you must have .NET framework 3.5.1 or 4.5 installed, otherwise the module won't work (if you can even install it in the first place).
You could install the module in your script with the following command:
Add-WindowsFeature RSAT-AD-PowerShell
Note that this feature requires the .NET Framework 3.5.1 feature too which can be installed with the following command:
Add-WindowsFeature net-framework-core
While you can install Active Directory on these machines just to run your code, I'd suggest setting up a session to a computer that already has it installed instead. If the Techs are hands on and have credentials to access AD then this will work better.
$Session = New-PSSession -ComputerName DC -Credential (Get-Credential) -Name AD
Enter-PSSession -Session $Session
Import-Module ActiveDirectory
Doing-AD -Stuff
...
Disconnect-PSSession
With this approach, the Tech will be prompted for their credentials, the script will run your AD stuff, and the client machine won't have RSAT tools enabled or installed.
Related
Currently I am trying to write a power shell script that will uninstall then install Microsoft Teams.
I have never written a power shell script before and I am having trouble having the script get the initial teams installation so I can uninstall it.
This is what I have written so far, I saw two ways of finding the teams install online and neither is able to find it so I am kinda lost, any help would be much appreciated.
(I know both are commented out I just did it like this for formatting in this question.)
Write-Host "-------------------------------------`n"
# Prompt for credentials
$credential = Get-Credential
$username = $credential.Username
$password = $credential.GetNetworkCredential().Password
Write-Host "Finding teams`n"
# Find teams 1
#$teamsapp = Get-AppxPackage -Name Microsoft.Teams
# Find teams 2
#$teamsapp = Get-WmiObject -Class Win32_Product | Where-Object { $_.Name -eq "Microsoft Teams" }
# Check if installed
if ($teamsapp) {
Write-Host "Microsoft Teams is installed."
} else {
Write-Host "Microsoft Teams is not installed."
}
`
Teams is a bit tricky because it installs per user, not per computer. Assuming you're running the script under the user's account, you can check the following registry location using Get-ChildItem:
Computer\HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Teams
This code worked for me:
Get-ChildItem -Path 'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\' | Where-Object { $_.Name -like '*Teams' }
You should be able to use the "QuietUninstallString" property of the result to get the command needed to uninstall Teams.
As a side note, consider looking into the Teams Machine Wide Installer for deploying teams. It installs to the computer and runs at logon for each user to detect if Teams is installed to their AppData folder. If not, it installs it automatically. This lets you avoid having to run as the user or loop through all the users AppData folder to manipulate user apps.
new to stackoverflow and novice at Powershell, so go easy.
I'm looking for a way for a Powershell script to check if specific modules are installed. If not then give a message asking if they would like to install those not installed. If all are installed then proceed with the script.
I've seen the '#requires -Module' option but I want to provide a better prompt rather than the Powershell red text.
For reference, I want to check if AzureAD, ExchangeOnlineManagement, and MSOnline modules are installed
Any help appreciated.
Regards,
Lee
To offer an alternative to Steven's helpful answer that handles the missing modules as a group :
# Define all required modules
$modules = 'AzureAD', 'ExchangeOnlineManagement', 'MSOnline'
# Find those that are already installed.
$installed = #((Get-Module $modules -ListAvailable).Name | Select-Object -Unique)
# Infer which ones *aren't* installed.
$notInstalled = Compare-Object $modules $installed -PassThru
if ($notInstalled) { # At least one module is missing.
# Prompt for installing the missing ones.
$promptText = #"
The following modules aren't currently installed:
$notInstalled
Would you like to install them now?
"#
$choice = $host.UI.PromptForChoice('Missing modules', $promptText, ('&Yes', '&No'), 0)
if ($choice -ne 0) { Write-Warning 'Aborted.'; exit 1 }
# Install the missing modules now.
# Install-Module -Scope CurrentUser $notInstalled
}
As alluded to in your question, there are a few ways to ensure modules are available to a script or module. Modules can define other modules as well as other prerequisites. #Requires can be used, but neither facility will prompt or otherwise install a module. Instead, they will prevent the loading or running of the dependent script etc.
If you want to start building a function you can check if a module is available on the given system with:
Get-Module -Name <ModuleName> -ListAvailable
You can wrap this in a loop with an If block to cover multiple modules:
ForEach( $Module in $RequiredModules )
{
If ( !(Get-Module -ListAvailable -Name $Module) ) {
# find, install and load the module.
}
}
I would draw your attention to the other *Module cmdlets to build out the remaining functionality you described.
Find-Module
Install-Module
Save-Module
Import-Module
I need to move PowerShell Az module from one machine to another offline (both machines have the same windows (10 Pro 1809), .net, powershell (5.1), etc versions)
I can't use either Private PowerShellGet Repositories or MSI installer
I run Save-Module -Name Az -Path 'C:\Users\kag\Documents\ps_modules' -RequiredVersion 3.7.0 -Force on "donor" machine and it gives me 50+ dirs exported:
I copy all to "receiver" machine and running:
Get-ChildItem "C:\Users\kag\Documents\ps_modules\*" -Recurse | Unblock-File
Import-Module -name "C:\Users\kag\Documents\ps_modules\Az" -Verbose
..but getting errors for all dependencies:
Any ideas how to correctly move Az module offline?
Here my comments as answer:
It seems the path you saved the module in C:\Users\kag\Documents\ps_modules is not one of the module paths PowerShell knows of.
You can test which paths are used by PowerShell to find your modules by typing
$env:PSModulePath.split(';')
in the console.
Below is an excerpt from Stefan Stranger's Blog
You can add a temporary path that is available for the current session only:
$env:PSModulePath = $env:PSModulePath + ";C:\Users\kag\Documents\ps_modules"
To make that permanent, you can either add the line above to your PowerShell profile, or manually add it to the registry:
$CurrentValue = [Environment]::GetEnvironmentVariable("PSModulePath", "User")
[Environment]::SetEnvironmentVariable("PSModulePath", $CurrentValue + ";C:\Users\kag\Documents\ps_modules", "User")
use "User" to store this path for the current user only. Use "Machine" to have that path available for all users
I am trying to install software using powershell silent scripting. To install this software we need to have JRE installed on machine. For this first we need to check weather JRE installed or not, if not installed then it needs to be installed. What approach needs to be followed?
I have tried with the below of code.
$LASTEXITCODE = 0
$workdir = "C:\Program Files (x86)\Java"
If (!(Test-Path $workdir))
{
$LASTEXITCODE = (Start-Process "D:\jre-6u26-windows-i586.exe" -ArgumentList "/s" -Wait -PassThru).Exitcode
}
If($LASTEXITCODE -eq 0)
{
$DCBdir = "C:\Program Files (x86)\Compart"
If (!(Test-Path $DCBdir))
{
$Installer="D:\sw.exe"
$responsefile="D:\Sresponse.varfile"
$a=#("-q", "-varfile", "$responsefile")
start-process $Installer -ArgumentList $a -wait
}
}
$chkdir = "C:\Program Files (x86)\SWFolder"
if(Test-Path -eq $chkdir)
{
[System.Windows.MessageBox]::Show('Installation completed successfully')
}
When I run script its workingfine as it is checking the previous installation and performing installation if not found the installation. But here I am getting as issue with this code.
If Java installed alredy means it should start the other installation. but here in my case its stopping the complete installation.
after installation completed, I need to display the message like " Installation completed". But here its not working. AnNy wrong in the above code..??
One package manager that I like to use is Chocolatey which has an approved package for JRE, it looks like. A quick check wmi will tell you whether or not java is installed:
$x = Get-WmiObject -Class Win32_Product -Filter "Name like 'Java(TM)%'" | Select -Expand Version
You could also use Test-Path pointed at registry keys you know exist for the package. Once you verify that JRE is not on the machine, then you can call out to Chocolatey to install it.
I'm looking to automate the process of installing WSUS updates on my VMs. To give a short overview, here are the things I want to accomplish (please let me know if my methods are moronic, I'd love to learn the right way for all of this.):
Check if the particular VM has any WSUS updates to install
If there are updates available, take a snapshot of the VM
Begin the WSUS install
Reboot the system, if necessary
I am currently able to check if the particular VM has updates and take a snapshot. Now I know I could just have this portion of the script run and configure a GPO to accomplish the rest of the tasks, but my thought process is that if I can do it all in the script, I will be able to check that the snapshot of the VM exists prior to installing the update. Below you can see what my script does as of now.
foreach ($vm in $vms) {
if ($vm.PowerState -eq "poweredOn") {
$output = Invoke-VMScript -ScriptText $script -VM $vm -GuestCredential $guestCred
if ($output.ScriptOutput -Notlike '0*') {
New-Snapshot -VM $vm -Name BeforeWSUS
}
}
}
After this I would like to perform a check to see if the snapshot exists for a vm, then install the WSUS update. If a reboot is necessary, then reboot.
Is there a way to do this? A better way to do this? Would really appreciate some insight, I'm new to Powershell.
Edit: I've checked on the PSWindowsUpdate Module, would that need to be on each VM I plan to update?
Yes, you would need PSWindowsUpdate installed on each VM.
You could include something like this in your script to check if PSWindowsUpdate is installed and if not, install it.
Set-PSRepository -Name "PSGallery" -InstallationPolicy Trusted
$Modules = "PSWindowsUpdate"
$Modules | ForEach-Object {
If (!(Get-Module -ListAvailable -Name $_)) {
Install-Module $_ -Verbose -Confirm:$false
}
}
I think that Install-Module requires PowerShell version 5.0.
Then you would use Get-WUInstall to install updates from your WSUS server. (It looks like it defaults to WSUS if configured via GPO.)
Probably throw in a -Confirm:$False to avoid it prompting you to allow each update.
More info on PSWindowsUpdate: https://github.com/joeypiccola/PSWindowsUpdate