I am using a powershell script to import GPOs which I have saved as GUIDs (the default).
I wish to import the GPOs on a different system, the GPOs are saved to a CD at this point. So a simple way to import a single GPO would be:
$domain=[System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain().Name
$import_array = get-childitem ($current_drive + $gpo_backup_location) | Select name
foreach ($GPO in $import_array) {
Import-GPO |
-backupgponame $GPO.name -path ($Current_Drive + $gpo_backup_location) |
-domain $domain |
-Targetname $GPO.name |
-migrationtable ($Current_drive + $mig_table_path) |
-Createifneeded;
}
}
the $import_array command gives me my folder names
Name
----------
GPO-1
GPO-2
GPO-3
GPO-4
and so on...
I want to iterate over these and import each one. The GPOs are saved using another block of code to backup the GPOs as their displayname. (GPO-1, GPO-2, etc.,)
I cannot for the life of me figure out how to force it to look at the folder name and to import these
EDIT
The Backup was created with the following code:
Function GPO_Backup_DisplayName ($MenuChoice) {
write 'Backing Up GPOs by Display Name'
Foreach ($GPO in $GPO_Temp_Backup) {
$GPOBackup = Backup-GPO `
-name $GPO.DisplayName `
-path ($Current_drive + $GPO_Backup_Location) `
-Domain $domain;
Get-GPOReport $GPO.DisplayName `
-reporttype HTML `
-Domain $domain `
-path ($Current_drive + $GPO_Backup_HTML_Report + $GPO.DisplayName + ".html");
Rename-item
-path ($Current_drive + $GPO_Backup_Location + "{" + $GPOBackup.Id + "}") `
-newname $GPO.DisplayName
}
}
If you export each GPO to its own folder and name that folder after the GPO, you can iterate over these folders in a foreach loop to import the GPOs and set the target name to the folder name. Something like this should work:
Get-ChildItem "C:\backup" | % {
$name = $_.name
$id = (get-childitem $_) -replace '[{}]', ''
Import-GPO -BackupId $id -TargetName $name -path $_.Path -CreateIfNeeded
}
Prerequisite is that you created the backups with something like this:
Get-GPO -All | % {
$name = $_.DisplayName
$dir = New-Item "C:\backup\$name" -Type Directory
Backup-GPO -Guid $_.Id -Path $dir
}
Also, the backup directory should contain only the folders with the single GPO backups, otherwise you'll have to add a filter between Get-ChildItem and ForEach-Object.
List Group Policy Object using PowerShell
Related
The following code does some queries locally on individual servers, and the desired result is accomplished. However I want to copy these files to a remote directory on our network for easy access. The issue I have run into is that I have added a random number to the file name to keep them unique, but how do I call the randomly named file to be copied. Obviously this would be easier without the random number, but I will be dumping multiple files into the desired directory. (also I commented out the remote location, as I have not settled on a directory yet) Hope that makes sense
=============================================================================
#Creates folder for the files to be stored
New-Item -Path 'C:\temp\ServerQuery' -ItemType Directory
#Grabs Device Name and Local user Accounts
Get-WmiObject -Class Win32_UserAccount -Filter "LocalAccount='True'" |
Select PSComputername, Name, Status, Disabled, AccountType, Lockout, PasswordRequired, PasswordChangeable, SID | Export-Csv C:\temp\ServerQuery\DeviceandUserAccounts.csv
Get-LocalGroup | Select Name, Objectclass, Principalsource, sid| Export-Csv C:\temp\ServerQuery\LocalGroup.csv
#Converts files to Excel workbook with Each file on a different sheet
$path="C:\temp\ServerQuery" #target folder
cd $path;
$csvs = Get-ChildItem .\* -Include *.csv
$y=$csvs.Count
Write-Host "Detected the following CSV files: ($y)"
foreach ($csv in $csvs)
{
Write-Host " "$csv.Name
}
#Random added to place a random variable in the file name so we do not have duplicates
$Random = Get-Random
$outputfilename = $(get-date -f MM-dd-yyyy) + "_" + $env:USERNAME +"_" + "$Random" +
"_Server_Query.xlsx" #creates file name with date/username
Write-Host Creating: $outputfilename
$excelapp = new-object -comobject Excel.Application
$excelapp.sheetsInNewWorkbook = $csvs.Count
$xlsx = $excelapp.Workbooks.Add()
$sheet=1
foreach ($csv in $csvs)
{
$row=1
$column=1
$worksheet = $xlsx.Worksheets.Item($sheet)
$worksheet.Name = $csv.Name
$file = (Get-Content $csv)
foreach($line in $file)
{
$linecontents=$line -split ',(?!\s*\w+")'
foreach($cell in $linecontents)
{
$worksheet.Cells.Item($row,$column) = $cell
$column++
}
$column=1
$row++
}
$sheet++
}
$output = $path + "\" + $outputfilename
$xlsx.SaveAs($output)
$excelapp.quit()
cd \ #returns to drive root
#Remove .csv files from folder in order to keep clean for the next query
Remove-Item -path C:\temp\ServerQuery\*.csv*
#Copy files to \\filesvr\GLOBAL drive for access
#$remoteFilePath = '\\filesvr\GLOBAL\File.txt'
#Copy-Item -Path C:\File.txt -Destination $remoteFilePath
#Write-Host "I've just copied the file to $remoteFilePath"
I'm BRAND new to ps scripting and am looking for some advice please.
We replace a data share server every couple of years, and creating the complete folder structure and permissions by hand is very tedious, so I'm trying to automate it with a powershell script. Since I'm new I've been googling for some examples and snippets and have been compiling what I need from it.
My export script reads the folder structure and rites it to a text file, and my import script creates it once I move the folder over to new server, no problem.
The problem comes with the access rights.
It reads the rights and writes it to a CSV, but once I try to import it I get an error:
new-object : Cannot convert argument "2", with value: "TRUE", for
"FileSystemAccessRule" to type
"System.Security.AccessControl.AccessControlType": "Cannot convert
value "TRUE" to type
"System.Security.AccessControl.AccessControlType". Error: "Unable to
match the identifier name TRUE to a valid enumerator name. Specify one
of the following enumerator names and try again: Allow, Deny"" At
line:1 char:23
... ccessRule = new-object System.Security.AccessControl.FileSystemAccess ...
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CategoryInfo : InvalidOperation: (:) [New-Object], MethodException
FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommand
As I understand it it's looking for a Allow/Deny and not a True/False, but the export gives a True/False. So I'm guessing there's something wrong with my export...
Here is my code if anyone could point me in the correct direction I would greatly appreciate it!!
(Let me know if I should post ALL the code, I just don't want to clutter any more than I already do :D)
Export:
$FolderPath = dir -Directory -Path $DriveLetter -Force
$Report = #()
Foreach ($Folder in $FolderPath)
{
if ($Folder.Name -notlike '*$RECYCLE.BIN*')
{
if ($Folder.Name -notlike '*System Volume Information*')
{
$Acl = Get-Acl -Path $Folder.FullName
foreach ($Access in $acl.Access)
{
$Properties = [ordered]#{'FolderName'=$Folder.Name;'IDRef'=$Access.IdentityReference;'FSRights'=$Access.FileSystemRights;'Inherited'=$Access.IsInherited}
$Report += New-Object -TypeName PSObject -Property $Properties
}
}
}
}
$Report | Export-Csv -path $ExportACL -NoTypeInformation
Import:
foreach ( $LItem in $ACL_Imp )
{
$path_full = $Drivepath.ToString() + $LItem.FolderName
$ACL_Set = Get-Acl $path_full
$permission = $LItem.IDRef, $LItem.FSRights, $LItem.Inherited
$accessRule = new-object System.Security.AccessControl.FileSystemAccessRule $permission <<<--- Error occurs here
$ACL_Set.SetAccessRule($accessRule)
$ACL_Set | Set-Acl $path_full
}
Example of one user in the export csv ( I remove the drive letter cause it isn't the same drive letter always.)
#TYPE System.Management.Automation.PSCustomObject;;; FolderName;IDRef;FSRights;Inherited
Data\UserA;Domain\UserA;FullControl;FALSE
Data\UserA;NT AUTHORITY\SYSTEM;FullControl;TRUE
Data\UserA;DOMAIN\UserB;FullControl;TRUE
Data\UserA;BUILTIN\Administrators;FullControl;TRUE
Data\UserA;DOMAIN\GRP_A;ReadAndExecute, Synchronize;TRUE
Data\UserA;Domain\GRP_A;ReadAndExecute, Synchronize;TRUE
Once again thanks in advance for any assistance!
And if you can't provide any, thanx for taking the time to check it out anycase!! :)
I've changed the number of variables I export and import, and that seemed to do the trick. (Exporting all variables, and only using 5)
I'm posting my Full Code in case someone else also wants to use this, or want to modify for their needs :)
Hope this will help someone in the future, and that my comments make sense..
Our Directory structure:
ImportExport <-- Location of scripts and output files (whole folder to be copied to new server)
Shared
Software
Users/UserA/
Users/UserB/
....
Users/UserZ/
Export:
#Variables
$drivepath = Get-Location #Get working drives' letter
$DriveLetter = Split-Path -qualifier $drivepath
$ExportACL = $DriveLetter.ToString() + "\ImportExport\export_acl.csv" #ACL Location
$ExportFolders = $DriveLetter.ToString() + "\ImportExport\export_folders.txt" #File with List of Folders
$UsersPath = $DriveLetter.ToString() + "\Users" #"Users" folders location on working drive located in Data folder
#Read user access levels on each folder on working drive and write to file.
cd.. #<-- add this if script is not run from within the PS environment.
$FolderPath = dir -Directory -Path $DriveLetter -Force
$Report = #()
Foreach ($Folder in $FolderPath)
{
if ($Folder.Name -notlike '*$RECYCLE.BIN*')
{
if ($Folder.Name -notlike '*ImportExport*')
{
if ($Folder.Name -notlike '*System Volume Information*')
{
$Acl = Get-Acl -Path $Folder.FullName
foreach ($Access in $acl.Access)
{
$Properties = [ordered]#{'FolderName'=$Folder.Name;'FSRights'=$Access.FileSystemRights;'ACType'=$Access.AccessControlType;'IDRef'=$Access.IdentityReference;'Inherited'=$Access.IsInherited;'IFlags'=$Access.InheritanceFlags;'PFlags'=$Access.PropagationFlags}
$Report += New-Object -TypeName PSObject -Property $Properties
}
}
}
}
}
$Report | Export-Csv -path $ExportACL -NoTypeInformation
#Read user access levels on each child folder of Users folders on working drive and add to file.
$FolderPath = dir -Directory -Path $UsersPath -Force
$UserReport = #()
Foreach ($Folder in $FolderPath)
{
if ($Folder.Name -notlike '*$RECYCLE.BIN*')
{
if ($Folder.Name -notlike '*ImportExport*')
{
if ($Folder.Name -notlike '*System Volume Information*')
{
$Acl = Get-Acl -Path $Folder.FullName
foreach ($Access in $acl.Access)
{
$StrFolderPath = $Folder.Parent.ToString() + "\" + $Folder.BaseName
$Properties = [ordered]#{'FolderName'=$StrFolderPath;'FSRights'=$Access.FileSystemRights;'ACType'=$Access.AccessControlType;'IDRef'=$Access.IdentityReference;'Inherited'=$Access.IsInherited;'IFlags'=$Access.InheritanceFlags;'PFlags'=$Access.PropagationFlags}
$UserReport += New-Object -TypeName PSObject -Property $Properties
}
}
}
}
}
$UserReport | Export-Csv -append $ExportACL
#Read Directory Structure and Export to File
$Dirs = Dir -Directory -Path $DriveLetter -Force
foreach($Dir in $Dirs)
{
if ($Dir.Name -notlike '*$RECYCLE.BIN*')
{
if ($Dir.Name -notlike '*ImportExport*')
{
if ($Dir.Name -notlike '*System Volume Information*')
{
$Dir.Name | out-file -Append $ExportFolders
}
}
}
}
$Dirs = Get-ChildItem -Path $UsersPath -Force
foreach($Dir in $Dirs)
{
$DirName = "Users\" + $Dir.Name
$DirName | out-file -Append $ExportFolders
}
Before import I open csv file in excel and make it different columns, so I use ";" as the delimiter, I'm struggling if I do not edit it. Variables with multiple values is split with a "," and that messes up the import.
Also, due to Admin rights needs to apply ACL, script needs to be run within elevated PS Environment, can't figure out how to do it outside. Can probably run a batch file to do a RunAs, but I had enough of this scripts for the time being. :p
Import:
#Variables
$drivepath = Get-Location #Get working drives' letter
$DriveLetter = Split-Path -qualifier $drivepath
$ImportACL = $DriveLetter.ToString() + "\ImportExport\export_acl.csv" #ACL Location
$ACL_Imp = Import-Csv $ImportACL -Delimiter ';' #Import ACL
$ImportFolders = $DriveLetter.ToString() + "\ImportExport\export_folders.txt" #File with List of Folders
$UsersPath = $DriveLetter.ToString() + "\Users" #Users' folder location on working drive
#Create Folders from text file.
Get-Content $ImportFolders | %{mkdir "$DriveLetter\$_"}
#Apply ACL to created Folder structure
foreach ( $LItem in $ACL_Imp )
{
$path_full = $Drivepath.ToString() + $LItem.FolderName
$ACL_Set = Get-Acl $path_full
$permission = $LItem.IDRef, $LItem.FSRights, $LItem.IFlags, $LItem.PFlags, $LItem.ACType
$accessRule = new-object System.Security.AccessControl.FileSystemAccessRule $permission
$ACL_Set.SetAccessRule($accessRule)
$ACL_Set | Set-Acl $path_full
}
I want to create a script which reads all the computernames from a CSV file. And from all of these, I want the description. Also it should be exported in a single CSV.
This is what I tried but...
$path = Split-Path -Parent $MyInvocation.MyCommand.Definition
$path_import_csv = $path + "\" + "Computernamen.csv"
$path_export_csv = $path + "\" + "Alessio.csv"
$computernames = Import-Csv $path_import_csv
foreach ($computername in $computernames) {
Get-ADComputer -SearchBase "OU=1,OU=2,OU=3,DC=my,DC=domain" -Properties * |
Select -Expand description |
Export-Csv -Path $path_export_csv -Append -Delimiter ";" -NoTypeInformation -Force
}
From your comment I gather that file Computernamen.csv is not a CSV file at all, but just a text file with computer names each on a separate line.
In that case, you do not use Import-Csv, but Get-Content to retrieve an array of computer names.
Also (others already made that clear) you are not using the $computername variable in the foreach loop at all AND by adding the -ExpandProperty switch to the Select-Object cmdlet, you are not receiving an object with property Description, but just the description as string .
For outputting a CSV with Export-Csv, you need to have a (series of) objects.
Also, I would recommend using the Join-Path cmdlet for creating file paths instead of contatenating string with + so you don't have to worry about possible missing backslashes.
Instead of $MyInvocation.MyCommand.Definition you can also use the $PSScriptRoot variable to get the current script path.
In Windows PowerShell 2.0, this variable is valid only in script modules (.psm1).
Beginning in Windows PowerShell 3.0, it is valid in all scripts.
$path = Split-Path -Parent $MyInvocation.MyCommand.Definition # or use $PSScriptRoot
$path_import_csv = Join-Path -Path $path -ChildPath 'Computernamen.csv'
$path_export_csv = Join-Path -Path $path -ChildPath 'Alessio.csv'
$computernames = Get-Content $path_import_csv
$searchBase = 'OU=1,OU=2,OU=3,DC=my,DC=domain'
$result = foreach ($computername in $computernames) {
# it is bad practice to use -Properties * if all you need is a small set of properties
$computer = Get-ADComputer -Filter "Name -eq '$computername'" -SearchBase $searchBase -Properties Name, Description -ErrorAction SilentlyContinue
# did we find a computer by that name?
if ($computer) {
# output an object with the two selected properties to get collected in the $result variable
$computer | Select-Object Name, Description
}
else {
Write-Host "A computer with name '$computername' does not exist."
}
}
# output the result on console
$result | Format-Table -AutoSize
# save the result as proper CSV file
$result | Export-Csv -Path $path_export_csv -Delimiter ';' -NoTypeInformation -Force
I backed up printers from a Windows 10 system to XML files. I'm trying to add them using the Set-Printconfiguration CMDLET, but it seems to be not accepting variables?
I've looked everywhere but I cannot find anything saying my syntax is wrong.
#get list of printers in backup folder
$printerNames = (Get-ChildItem -Path c:\temp\printers\*.xml -Recurse | select name).name
foreach ($printer in $printerNames)
{
Set-PrintConfiguration -PrinterName $printer -PrintTicketXml c:\temp\printers\$printer
}
Here is the code I used to get the printer XML files:
$TARGETDIR = "c:\temp\printers"
if(!(Test-Path -Path $TARGETDIR )){
New-Item -ItemType directory -Path $TARGETDIR
}
# Get all the printers:
$PN = (get-printer | select name).name
# Foreach loop to create XML file for each printer configuration
Foreach ($P in $PN){
$GPC = get-printconfiguration -PrinterName $P
mkdir c:\temp\printers\$P
$GPC.PrintTicketXML | out-file C:\Temp\printers\$P.xml
# $p|select *|out-file -Path c:\temp\$p.xml -NoTypeInformation
}
edit: here is the error I'm getting:
Set-PrintConfiguration : The specified printer was not found.
At U:\PowerShell\Scripts\backup\newRestorePrinters.ps1:15 char:9
+ Set-PrintConfiguration -PrinterName $printer -PrintTicketXml ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (MSFT_PrinterConfiguration:ROOT/StandardCi...erConfiguration) [Set-PrintConfiguration], CimException
+ FullyQualifiedErrorId : HRESULT 0x80070709,Set-PrintConfiguration
edit
I added more variables to get the list of printers w/out the .XML on the end of the names. It still gives me the same error output. It looks like it's not passing my variables to the set-printconfiguration command?
New restore script code:
$printerShortNameList = (Get-ChildItem -Path c:\temp\printers\*.xml -Recurse | select name).name
foreach ($shortName in $printerShortNameList)
{
$shortName.Replace('.xml', "x")
}
#get list of printers in backup folder
$printerNames = (Get-ChildItem -Path c:\temp\printers\*.xml -Recurse | select name).name
foreach ($printer in $printerNames)
{
Set-PrintConfiguration -PrinterName $shortName -PrintTicketXml c:\temp\printers\$printer
}
What was the error message? Shouldn't you take the '.xml' off the end of $printer for the printer name? I think you have to use add-printer first. I don't believe Set-PrintConfiguration creates printers.
On the bottom when you make the xml files, why do you create the c:\temp\printers\$p directory?
Set-PrintConfiguration:
You need administrator credentials to use Set-PrintConfiguration.
My Copy-Item doesn't work when included in a foreach loop.
Much like Powershell: Copy-Item not working when in ForEach loop
Only my destination folder is not set the same as the originating folder which seemed to be the problem there.
This is the very basic function. My objective is to grab the latest log files from a directory containting log files for lots of stuff. I'm only interested in a few defined in $servers. A line in Servers.txt looks like this: \\clientname\d$\logdirectory\processlog\
When I Set-Location to a path in servers.txt and run Get-ChildItem it works as expected.
I also need to generate a new folder for each object in \Logs\ but one thing at a time.
$servers = #()
$servers = Get-Content c:\Test\Servers.txt
$destServer = #()
$destServer = ( "clientname")
$destinationFolder = "\\" + $destServer + "\d$\Logs\"
foreach ($serverpath in $servers) {
Write-Host " Copying from $serverpath "
Set-Location -literalpath $serverpath |
Get-ChildItem |
Sort-Object -Descending LastWriteTime |
Select -First 2 |
Copy-Item -Destination $destinationFolder -Recurse -Force
}