Quantcast
Channel: admin | Alex Computer Bubble Blog
Viewing all 40 articles
Browse latest View live

Automated Expiry of Group Membership

$
0
0

Overview

This is the third blog in a series of posts about membership management of the (security/distribution) groups in Active Directory. The first one described the PowerShell scripts used to automate creation of Active Directory objects (such as groups and users, adding group members, etc.). In the second one I’ve presented a PowerShell script which creates an interface or a GUI tool to help group managers to manage groups in Active Directory. Finally, in this blog I will add the expiry component to the GUI tool and enable the group managers to automate expiry of the groups’ members.

Links to the previous groups’ management posts:
http://www.alexcomputerbubble.com/delegate-management-of-a-group-part-one/
http://www.alexcomputerbubble.com/delegate-management-of-a-group-group-manager-application-part-two/

The idea came to me after reading Technodrone blog which talks about setting a time limit on group membership.

I wanted more options for a group manager. For example, an option to select just one or a few members from a group and set the same or different expiration date for each individual member; or an option to set the same expiry date for all the members of a group and apply it to just selected members or to all newly added members as well. In order to provide these options, I’ve added the expiry tab to the Group Manager Application and created a PowerShell script that runs as a Scheduled Task on the server. The picture below is an attempt to graphically describe this process:

ProcessGroupExpiry

Figure 1: Automated Expiry of Group Membership

  1. Group Manger Application runs on client computers and uses ADSI to manage groups’ membership (adding, removing members, and expiry);
  2. For each security group being set with automated expiry of group membership, a configuration file (with the same name as sec. group) is written to a Folder stored on a Network Share;
  3. PowerShell script run as a Scheduled Task, and processes all the configuration files found in a Folder on a Network Share;
  4. Expiry Log file is written (successes and errors) to a Folder on a Network Share and contains one line for each and every security group processed;
  5. Changes to the security groups are written back to the log files and (in a case that a member is being removed from the group membership) back to the Active Directory.

Download and System Requirements

To download this application (a PowerShell script turned into an executable by SAPIEN PowerShell Studio ISE); please go to the download page – Application section. There are multiple files available in this download:

– CG.Option.XML
– Manage-GroupMembersWithExpiry_x64.exe
– Manage-GroupMembersWithExpiry_x86.exe
– Process-GroupMembersExpiry.ps1

The requirements for the Group Manger Application are as follows:

  1. Microsoft PowerShell version 3.0 is required with the execution policy set to ‘remotesigned’ on all client computers where this application will be used;
  2. Install Quest One ActiveRoles Management Shell for Active Directory executable on all client computers where this application will be used;
  3. Install PowerShell version 3.0 on Server 2008 R2.

3.1. Before installing Windows Management Framework 3.0, uninstall any previous versions of Windows Management Framework 3.0.
3.2. Make sure you have installed Service Pack 1
3.3. Install the full installation of Microsoft .NET Framework 4.0 (dotNetFx40_Full_setup.exe) from the Microsoft Download Center at http://go.microsoft.com/fwlink/?LinkID=212547.
3.4. Install Microsoft .NET Framework 4.5 (dotNetFx45_Full_setup.exe) from the Microsoft Download Center at http://go.microsoft.com/fwlink/?LinkID=242919.
3.5. Install Windows Management Framework 3.0 from the Microsoft Download Center at http://go.microsoft.com/fwlink/?LinkID=240290.

Install instructions

  1. Download the package; it contains both 32-bit and 64-bit executable.
  2. On a client computer:
    2.1. Unzip the download and make sure that these two files are in the same folder: CG.Option.XML and Manage-GroupMembersWithExpiry_x64.exe (or _x86.exe).
    2.2. Edit the content of the CG.Option.XML file to reflect your environment. There are three lines to be edited as shown in the picture below.

CGOptionFigure 2: CG.Option.XML file

Firstly, you have to specify the OU that contains all the security groups that will be managed by this application. Secondly, write the DN of the security group that acts as a manager. Thirdly, specify a network path to the Network Share / Folder that will contain all the configuration and log files that this Application creates while processing groups’ members. A security group designated as a manager must have up to Modify access to this Network Folder.

    3. On a server:

3.1. From unzipped folder, place the Process-GroupMembersExpiry.ps1 script in any folder where it could be accessed by the account running a Schedule Task. In my example: “G:\Common\PowerShellScripts\Process-GroupMembershipExpiry.ps1”.Edit two lines (variables) in this script to reflect your environment: the first variable is the path to the Network Share / Folder that contains all the configuration and log files as described under 2.2.

My example: $dirLogFolder = “G:\Common\Logs”

Make sure that the account running a Scheduled Task has access to these Folders.
The second variable is a path to the Log files that will be created by this Application.

 My example: $dirSource = “G:\Common\GroupMemberExpiry”.

3.2.Create a Scheduled Task.

Start by creating a Schedule Task as shown in the picture below:

CreateTask1

Figure 3: Create Task – General tab

Set a trigger, in my example: Daily, recurring every day as shown below:

SetTriger1

Figure 4: Create New Trigger

On the Action Tab specify to start a program and type Details as shown in the picture below:

CreateTask_NewAction1

Figure 5: Create Task – Action tab, type: PowerShell.exe -ExecutionPolicy Bypass -command & (“{G:\Common\PowerShellScripts\Process-GroupMembershipExpiry.ps1}”)

Once the Task has been created (in my example named: GroupMemberExpiry), you will be able to see it the Task Scheduler Library, as shown below:

ViewTask

Figure 6: Task Scheduler Library

    A Scheduled task will run every day, and you have to make sure the account that will run the task is an Administrator or a member of the Local Security Policy “Log on as a batch job”. To good practise would be to assign a dedicated AD account to run this task. Note that the permissions for this account have important role: make sure the account you use for this job has the rights to write/delete files inside the parent directory of this script (as described under 3.1.), has access to the Active Directory OU, and the rights to change the groups’ objects contained by AD OU.

How Application Works

Application provides a tool for group managers to manage and update groups’ membership as well as to automate expiry of groups’ members. This application, in its second, updated version has two tabs: Group Membership Administration and Group Membership Expiration. Please read the second blog first to find out how this application could be used to manage group’s membership. Here, in this blog, I will give you a description of the expiry component of the application and present only the portion that enables group managers to manage expiry of groups ‘members.

In my AlexTest.Local domain, I have Groups OU which contains three sub-OUs: Accounting, Sales and Warehouse. The security group, named AFL-GroupManager, has been designated as the group manager of all security groups housed in these sub-OUs.

AD_Groups Figure 7: AlexTest.Local domain – Groups organizational unit

In the picture below, you can see the properties of two security groups in Accounting OU.

AD_GRoupManagerFigure 8: example of two security groups – Managed By tab

To manage groups’ membership expiration, please start the application and click on the Group Membership Expiration tab, as shown in the picture below.

GroupManager_ExpiryTab

Figure 9: Group Membership Expiration tab

To expose the members of the groups, you would click/select the group name from the Manged Security Groups list (in my example: AFL PQR 06), and the selected group’s members would be listed in the box on the Group Membership Expiration tab. There are two radio buttons that you could use to either set expiration for the individual members of the selected group or set the expiration date for all the (present/existing) members of the group. Under the first option, there is a button named Get Expiry Date which, when clicked, will display the expiry date for the selected group that has been configured for expiration of its members. The latter option has a check-box to include all newly added members. For example, you have a group that currently has 10 members, and you use the latter option to set expiry for all existing 10 members. You set expiry date to be 60 days from now. All current members would expire and therefore be removed on the same day, except the members that were added to this group sometime after the group’s membership expiry has been set.  If you have selected the check-box, all newly added members (even those added to the group the very last day) would expire on the same day as the rest of the group members.

See in the picture below an example of setting individual members expiration in the picture below. There are five members, and the expiry days are different for each and every member. I’ve typed the numbers next to the group’s members; made sure the check boxes had been selected and pressed the Set Group Expiration button. I could, if I wanted to, to set the same number of days for each group’s member instead.

SelectMembersToExpiry

Figure 10: Setting individual members expiration – group named: AFLVWX 08

The second example shows setting the expiration date for the present group’s members. I’ve selected the security group named AFL GHI 03 and set the expiry date to be December 20, 2014. Once the expiration has been configured and the configuration file created, the numbers will appear under Days column, showing the numbers of days left (in my example 30 days). If you open this application in next ten days, and select under this tab the group named AFL GHI 03, the Days column will display number 20 as the number of days left. Please note the configuration file named as same as this group, which has three columns, but only two (“SamAccountname”,”Number”) of them have values.

SetExpiryForAllMembers

Figure 11: Setting the expiration date for all present members

The third example is a graphical explanation of setting up the expiration date for all existing members and all the newly added members that could be added to the group by Help Desk agents. The group name is AFL DEF 02, and the configuration file, just as the grid on the Expiry Tab, shows the number 7 as the number of days set for expiry of all members, current and the newly added. Note the column with name Submitted in the configuration file. It has values set for all the members. This column is named Limit in the grid on the Expiry Tab.

SetExpiryForAllMembersAndNewOnes

Figure 12: Set expiration for existing and all newly added members

Let’s see the back-end of this application. On the server side, there are two folders that are populated with groups’ configuration files and the log files. The main engine here is the PowerShell script (named: Process-GroupMembershipExpiry.ps1) that is running as a Schedule Task. The picture below shows two folders with configuration and log files.

ShareFolderFilesFigure 13: Folders containing configuration and log files

The Process-GroupMembershipExpiry.ps1 script runs as a Scheduled task every day, and while it processes the configuration files inside the GroupMemberExpiry folder, it logs its actions (one line per security group) in the Logs folder. See the picture below.

ExpiryLog_MoreFiles

Figure 14: Expiry Log and three groups’ configuration files

The following picture shows the result of the removal of groups’ members by a script.  The group named AFL STU 07 had been configured for removal of all members, while the group named AFL ABC 01 had only one member removed – Mr. Blue. RemovalOfMembers_Log

[Figure 15: Removal of group members by script

I do apologize for the length of this post, and I hope that it will help you not just understand but implement or test this solution in your environment.




Please note: Although the author has made every reasonable attempt to achieve complete accuracy of the content, he assumes no responsibility for errors or omissions. Also, you should use this information as you see fit, and at your own risk.


USB Drives – List Connect Share

$
0
0

In this post I want to share with you one of my HTA utilities created for viewing all USB sticks/devices that are currently plugged into a remote network computer, creating a share on remote computer and viewing the content of the shared USB stick on a remote computer. In addition, I wanted to use this HTA tool to view a user logged into a remote computer and, if required, disable or enable the usage of USB sticks in order to prevent users from connecting to USB storage devices on a remote computer.
The picture below shows the simple interface of this HTA tool named “USB Drive Info”.
UsbDriveInfo_App_01 Figure 1: USB Drive Info application

In order to see if there is any USB devices connected to a remote networked computer, I just need to type the name of a remote computer (in my example: TEST-AFL-XYZ007 or its IP address) and click the top button on the right “View USB Drives”. If the remote machine is online, and has USB sticks plugged in, the list of USB Flash Drives will display all connected devices showing their info such as Model, Size, Drive Letter and devices’ serial numbers. Please see the example in the picture below.

UsbToolKit_ListOfUsb

Figure 2: USB Drive Info displays the list of USB sticks plugged into the remote computer

To connect and share USB stick (model name Lexar JD FireFly) represented by G: letter drive, I only need to click on the button “Create Share/Connect” in the same row (row number 2) as this USB device, and if successful, the popup window will display message “TEST-AFL-XYZ007 created USB Share named G – success”, as shown in the picture below.

UsbToolKit_ShareConnectGDrive

Figure 3: Creating USB share on a remote computer ( \\TEST-AFL-XYZ007\G ).

Once the USB share is created, the button in the corresponding row will be changed as well. To remove this share, just click the button “Remove Share/ Disconnect”, as shown in the picture 4.

UsbToolKit_RemoveShare

Figure 4: To remove the share, click the button “Remove Share/ Disconnect” in the matching row.

If I want to disable the usage of USB sticks in order to prevent users from connecting to USB storage devices on this remote computer, I only need to click on the button “Enable/Disable All USB”, and the popup window will prompt me to confirm my decision, as shown in the picture 5. The usage of USB sticks connected to a remote computer could be enabled again by clicking on the same button.

UsbToolKit_DisableEnableUsb

Figure 5: Disabling USB sticks on the remote computer TEST-AFL-XYZ007.

If you find this tool useful and want to test it in your environment, please note that you have to run it as a user that have admin access to the remote computers. To run HTA program elevated via the Right Click Menu – Run as Administrator, please see my blog Run a Program Elevated via the Right Click Menu – Run as Administrator.




Please note: Although the author has made every reasonable attempt to achieve complete accuracy of the content, he assumes no responsibility for errors or omissions. Also, you should use this information as you see fit, and at your own risk.

WinPE 5.0 GUI – Create Bootable ISO

$
0
0

In the post about WinPE 5.0 GUI, I’ve described the steps to build a bootable USB stick with a dual-boot WinPE 5.0 boot image. In the case that you need a dual-boot WinPE image in an environment that restrict use of USB drives, you can use Oscdimg command-line tool to create an image (.iso) file of a dual-boot WinPE 5.0, and then burn the .iso file to a CD or DVD.

Oscdimg Command-Line Tool

My assumption is that you have Windows ADK 8.1 installed, downloaded a WinPE-Plugin.zip package and run (as administrator) the PowerShell script named DualBoot-WinPE50.ps1. This script creates under WinPE-Plugin folder four subfolders: Media, Mount, WinPE50_amd64 and WinPE50_x64, see the picture here:

WinPE-PluginFolderAfter

Picture 01: content of WinPE-Plugin folder

The presence of the Media folder is important; it is the source location for our Oscdimg.exe tool.

Start command-line as administrator and make Oscdimg your current directory (e.g. cd C:\Program Files (x86)\Windows Kits\8.1\Assessment and Deployment Kit\Deployment Tools\x86\Oscdimg).

Type the following command: Oscdimg -bootdata:2#p0,e,bEtfsboot.com#pEF,e,bEfisys.bin -u1 -udfver102 C:\WinPE-Plugin\Media C:\WinPE-Plugin\DualBootWinPE50.iso

OSCDimg

Picture 02: creating DualBootWinPE50.iso file

Note the syntax in this command: Oscdimg [<options>] <sourceLocation><destinationFile>

In the example above I’ve created a bootable DualBootWinPE50.iso file (use CD or DVD) for a UEFI-based or BIOS-based computer by using a multi-boot command. Note the following in the above command:

  • The bootdata option must be followed by the number of boot entries in the command (-bootdata:<number>).
  • Each multi-boot entry must be delimited by using a hash symbol (#).
  • Each option for a boot entry must be delimited by using a comma (,).
  • Each boot entry must specify the platform ID.

In addition, the C:\WinPE-Plugin\Media folder is the source location and the C:\WinPE-Plugin\DualBootWinPE50.iso is the destination file.




Please note: Although the author has made every reasonable attempt to achieve complete accuracy of the content, he assumes no responsibility for errors or omissions. Also, you should use this information as you see fit, and at your own risk.

WinPE – Dual Boot External USB Drive

$
0
0

It’s always a good habit to back-up your computer; the saying goes that computers’ users could be divided into two groups: ones that do backup and the others that are sorry.
This post is the fourth one in the series of posts about Microsoft WinPE (i.e. Windows Preinstallation Environment is a minimal operating system with limited services, built on the Windows kernel). In my second post about WinPE 5.0 GUI, I had provided information and scripts about the requirements and steps to be taken in order to build an interface for WinPE using Microsoft PowerShell.

LaptopWitDrive

ImageX is a command-line tool that enables original equipment manufacturers (OEMs) and IT professionals to capture, to modify, and to apply file-based disk images for rapid deployment. I am sure that everyone could use ImageX to do a backup. ImageX allows you to take complete backup of a Windows® volume and save an image to a file. You can then restore any system with its original image in just a few minutes as long as you apply it on the same hardware.

 Note:The solution explained in this post provides scripted way to capture, and to apply file-based disk images using ImageX.exe tool. It does not provide scripted way to use Sysprep, a tool used (by IT professionals) to configure new installations of Windows for duplication, prior to capturing image by ImageX. You could use my WinPE – Dual Boot External USB Drive application on a computer without running Sysprep /generalize to backup your computer’s Windows® partition. Moving or copying a Windows image to a different computer with different hardware without running sysprep /generalize is not supported.

There is an ongoing SID debate: to Sysprep or not to Sysprep. Mr. Mark Russinovich, a software engineer and author who works for Microsoft as a technical fellow, has addressed this issue in his blog: http://blogs.technet.com/b/markrussinovich/archive/2009/11/03/3291024.aspx

My position is that you can capture a non sysprepped image of your home computer or a workgroup computer. You should capture a non sysprepped image of a reference computer just prior to running Sysprep tool, and you have to sysprep an image in Active Directory / Windows Server Update Services (WSUS)) domain environment.

To determine whether a computer system has previously been sysprepped, look under the following registry key: HKEY_LOCAL_MACHINE\System\Setup

If you find a value named CloneTag under this key, the system has been sysprepped (i.e. generalized) and the value of this key will tell you when this was done (https://support.microsoft.com/en-us/kb/180962).

How the WinPE – Dual Boot External USB Drive gets installed

  • You need to have Windows ADK 8.1 installed; download the Windows Assessment and Deployment Kit (Windows ADK) for Windows 8.1 Update here: http://www.microsoft.com/en-us/download/details.aspx?id=39982.
  • Download WinPE-DualBootExternalUSBDrive.zip package from the download section, under Application folder. After you download the file, please do the following:
  1. Unzip the file (for example C:\ WinPE-DualBootExternalUSBDrive).
  2. Connect your external USB Drive to your computer.
  3. Find the Create-DualBootExternalUSBDrive_x64.exe file (there are two files: one for 32 bit and one for 64 bit architecture, I am using in my example the 64 bit executable).
  4. Ran as administrator the Create-DualBootExternalUSBDrive_x64.exe tool in order to create Media files that are necessary to make the external USB drive bootable.

This is a two steps process, please see the picture below:

CreateDualBoot_01

Picture 01: in the first step you will create Bootable Media files

During the first step, please select the folder named WinPE-DualBootExternalUSBDrive by clicking ‘Browse Source’ button, and once this folder is selected, please click ‘Start’ button to start creation of the Media files (i.e. the files and applications essential for dual booting USB drive). Please do not close PowerShell Command line windows as shown below.

CreatingMedia_01

Picture 02: Media files being created, do not close command line window

Once all Media files are created, please proceed to the second step in order to make USB Drive bootable. First click on ‘View USB Drive(s)’ button to display all available USB drives; select one or more USB drives form the list, and (for ones that you want to make bootable) click ‘Run’ button. See the pictures below. Please note that this process will delete any data previously stored on the selected USB drives.

CreateDualBootUSB_01

Picture 03: selected external USB Drive is being formatted

CreateDualBootUSB_02

Picture 04: Media files are copied to the selected USB drive

Finally, at the end of the second step, you will have a bootable USB drive. If you explore the contents of the newly created USB drive you will see the list of folders as displayed in the picture below.

USBDriveFolders

Picture 05: List of folders and files on the newly created external USB drive

Please do not delete any of the listed folders; note the ‘Images’ folder (with two subfolders: 32-BIT and 64-BIT) which serves as a container for all 32 bit and 64 bit images and the ‘Owner Files’ folder, which purpose is to house all the data files that you want to have stored on the external USB drive.

How WinPE – Dual Boot External USB Drive works

To see how your external USB drive works, please connect it to your computer (IMPORTANT: you should not connect/plug into your computer any other USB drives except this one), power up the computer and press the key that will display the boot option menu. After you get to the boot menu, locate the bootable USB device and then choose USB drive to boot from.

Please remember that we have dual boot USB drive, and at the very beginning you will have to choose to boot into either “WinPE5.0_x86–32BIT” or “WinPE5.0_x64–64BIT”. In my example, I select 64 BIT option and with this option the ‘Images\64-BIT’ folder on external USB drive is predetermined to house all my captured images and/or to display the ones previously captured.

As soon as the computer finalizes booting into external USB drive, the application with three tabs appears: Computer Info, Create Image and Apply Image. On all tabs there is an image, named “Computer Hard Drive”, courtesy of “FrameAngel” at FreeDigitalPhotos.net.

The first tab, The Computer Info, displays info about computer’s hardware (make, model, serial, NIC, etc.) and the content of the external images folder. By clicking on ‘Delete’ button, you can delete the checked image files and their descriptions; the rest of the buttons you can use to refresh displayed info, to restart or shutdown a computer.

WinPEusb_ComputerInfo

Picture 06: displays info about computer’s hardware and captured images inside Images folder.

The second tab, Create Image, as shown in the picture below displays the process of capturing an image. You have to provide the name of the image file while the description is optional. I would strongly suggest that you always provide a description for an image in a form of an answer to the 5Ws.

WinPEusb_Capture

Picture 07: displays the process of capturing an image.

The third tab, Apply Image, lists all the previously created images that you can use with this WinPE. For example, you would first select an image file and click on ‘Apply’ button to start the process of applying image on the computer’s hard drive as shown in the picture 08.

WinPEusb_Apply

Picture 08: displays the process of applying selected image file.

Important: when you apply an image, the computer’s hard drive will be formatted; the scripted process creates two partitions, a hidden one that is 300 MB in size (i.e. system reserved partition used for bootmgr and bitlocker), and the remaining hard drive space is used to create a second partition. At the end the script makes Windows partition bootable.

WarningMessage

Picture 09: Warning message – only one drive detected.

To download the WinPE – Dual Boot External USB Drive application, please go to the site’s download section, and expand the Application folder.




Please note: Although the author has made every reasonable attempt to achieve complete accuracy of the content, he assumes no responsibility for errors or omissions. Also, you should use this information as you see fit, and at your own risk.

Automate Driver Installation

$
0
0

The drivers can be installed in different ways, but when installed, they are loaded into the folder named: ‘DriverStore’, which is located under %SYSTEMDRIVE%\Windows\System32\DriverStore. You can use different command line tools to populate this driver store as follows:
1. PnPutil is a command-line tool that is included in every version of Windows, and the following example show how it can be used with PowerShell script to add and install driver.

$driversCollection = (Get-ChildItem -Path C:\MyDriversFolder -Filter "*.inf" -Recurse -ErrorAction SilentlyContinue | 
Select-Object -ExpandProperty Fullname)
foreach($driver In $driversCollection){
&amp;nbsp;&amp;nbsp;&amp;nbsp; 	# Add and install driver package
&amp;nbsp;&amp;nbsp;&amp;nbsp; 	pnputil.exe -i -a $driver
 	} 

2. DISM is a command-line tool that can be used to service a Windows image and therefore to add driver packages with the following servicing options available for an offline image.
DISM.exe /image: [/Get-Drivers | /Get-DriverInfo | /Add-Driver | /Remove-Driver | /Export-Driver]
An example:

$MountPath = “C:\Images\Win7OffLine”
$WimFile = “C:\Images\Win7.wim"
$driverFolder = "C\Drivers\HP EliteBook 850\HP_ZEP_G1_W7_X64_A1.106\x64_win7"
# ---------------------------------------------------------------------------
# MOUNT
If(!(Test-Path $MountPath)){New-Item -Path $MountPath -ItemType directory}
    	dism.exe /Mount-Wim /WimFile:$WimFile /index:1 /Mountdir:$MountPath
#INJECT DRIVERS
# --------------------------------------------------------------------------
If(Test-Path -Path $driverFolder){
    	dism.exe /Image:$MountPath /Add-Driver /Driver:$driverFolder /Recurse
}
# UNMOUNT
# --------------------------------------------------------------------------
dism.exe /Unmount-Wim /Mountdir:$MountPath /commit
 

I have used both PnPutil and DISM to install drivers in different scenarios, but always wanted a command-line app that will overcome limitations of the aforementioned tools. Firstly, if you have an unsigned driver, pnputil.exe will be prompted with the message “Windows can’t verify the publisher of this driver software”, and you will need to click Install to allow installation to proceed, and secondly, DISM.exe commands and options depend on whether the image is currently online (running an operating system) or the system is offline; unfortunately you cannot use DISM.exe when the system is online for the purpose of loading/removing drivers.
Starting with Windows 7, the Windows Driver Kit (WDK) includes version 2.1 of DPInst.exe command line tool that will silently install signed and unsigned drivers on a Windows running operating system. Being part of the Windows Driver Kit (WDK), you have to download kits and tools for Windows in order to obtain DPInst.exe. To download WDK, please use this link: http://www.microsoft.com/whdc/devtools/WDK/default.mspx

DPInst Example:
Please note that there are separate x64 and x86 dpinst.exe executable. Always use the latest version for your scripts. In this example, I will present a PowerShell script that I use with SetupComplete.cmd file to finalize installation of drivers after Windows Setup completes.
I place all my drivers inside C:\Driver folder as shown in the pictures below:

DriverdFolderPicture 1: Driver folder with all the drivers sorted by Manufacturer and hardware Model

DriverdFolder02Picture 2: displaying drivers available for hardware Model – “HP EliteBook 8540p”

As you can see, I prefer to create a folder for each Manufacturer and a subfolder for each hardware Model. Having this well organized Driver folder structure helps me to be very granular of what drivers are available during installation. To find out computers’ Manufacturer and Model, I usually use WMI Win32_ComputerSystem class, but you can run the MSInfo32 command and from its output write down the values for System Manufacturer and System Model items.
Here is the PowerShell script:

# Filename:	InstallDriver.ps1
# Date:		Oct 2015
# Author:	Alex Dujakovic
# Description:  PS script to inject/install drivers  
# ===================================================================

$driverFolder = "C:\Driver"
$installDriverLog = "C:\Windows\Temp\DriverLog.log"

$m = (Get-WmiObject -Class Win32_ComputerSystem -Property * |
Select-Object -Property Manufacturer, Model)
Write-Host "Manufacturer is: $($m.Manufacturer)" -ForegroundColor Green
Write-Host "Model is: $($m.Model)" -ForegroundColor Green


Function InstallDriver($path){
$x = (Get-ChildItem -Path $path -Recurse -Filter "*.inf" | select -Property Directory)
    foreach ($i In $x){
        try{
            $errorActionPreference = "Stop" 
            # Installing driver
            Write-Host "Installing driver: $($i.Directory.FullName)" -ForegroundColor Yellow
	        C:\Driver\dpinst.exe /path "$($i.Directory.FullName)" /lm /s /sa | Out-Null
            "Installing driver: $($i.Directory.FullName)" | 
            Out-File $installDriverLog -Encoding ascii -Append
        }
        catch{
            Write-Host "Error installing driver: $($i.Directory.FullName)" -ForegroundColor Red
            "Error installing driver: $($_.Exception.GetType().FullName)" | 
            Out-File $installDriverLog -Encoding ascii -Append
            "Exception Message: $($_.Exception.Message)" | 
            Out-File $installDriverLog -Encoding ascii -Append
        }
     }
}

$p = (Get-ChildItem -Path "$($driverFolder)" -Recurse -Directory -Filter "$($m.Model)" | 
Where-Object -FilterScript {$_.Name -match "$($m.Model)"} |
Select-Object -Property FullName)

If (!($p.FullName -eq $null) -and (Test-Path "$($p.FullName)")) {
    InstallDriver -path "$($p.FullName)" | Out-Null
    Write-Host "Finish driver installation" -ForegroundColor Green
}
Else{
    Write-Host "Folder with drivers for Manufacturer: '$($m.Manufacturer)' `
    - Model: '$($m.Model)' not found" -ForegroundColor Red
    "Folder with drivers for Manufacturer: '$($m.Manufacturer)' - Model: '$($m.Model)' not found" | 
    Out-File $installDriverLog -Encoding ascii -Append
}

And here is the SetupComplete.cmd file example:

start “Driver Installation” /wait C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile -WindowStyle Normal -ExecutionPolicy ByPass -File “C:\Driver\InstallDriver.ps1”

Note that commands in the Setupcomplete.cmd file are executed with local system privilege. After Windows is installed, but before the logon screen appears, Windows Setup searches for the SetupComplete.cmd file in the %WINDIR%\Setup\Scripts\ directory. If a SetupComplete.cmd file is found, the file is executed. Windows Setup logs the action in the Setupact.log file. You cannot reboot the system and resume running SetupComplete.cmd. The functionality of Setupcomplete.cmd differs from the RunSynchronous and RunAsynchronous commands in that Setupcomplete.cmd runs after Windows Setup completes while the RunSynchronous and RunAsynchronous commands run during Windows Setup.

 

UEFI Bootable External USB Drive

$
0
0

In this blog I am going to discuss how to create a bootable USB drive for UEFI (Unified Extensible Firmware Interface) devices running Microsoft operating systems (Windows 8.1 or Windows RT 8.1). As an owner of a UEFI system such as Surface Pro, you could use a bootable USB drive as a recovery media or maybe to create and deploy images. But there is an obstacle; UEFI based systems require that all boot files reside on FAT32 partition which has a 4GB individual file size limitation. If any of the image files to be deployed are larger than 4GB you would not be able to store that file on the USB drive with formatted FAT32 partition. To work around this problem, you have two alternatives:

Split a Windows image file

Deployment Image Servicing and Management (DISM) tool supports the /split-image command and could be used as described in the following example:

Dism /Split-Image /ImageFile:C:\install.wim /SWMFile:E:\images\install.swm / FileSize:4700

  1. C:\images\install.wim is the name and the location of the image file that you want to split.
  2. E:\images\install.swm is the destination name and the location for the split .wim files.
  3. 4700 is the maximum size in MB for each of the split .wim files to be created.

To apply an image from the E:\Images folder using DISM /Apply-Image command, type the following:

Dism /apply-image /imagefile:install.swm /swmfile:E:\Images\install*.swm /index:1 / applydir:C:\

As you can see it is possible to use wildcard characters. For example, “E:\images\install*.swm” will apply all of the split files in the E:\image directory named install1.swm, install2.swm, and so on.

Create multiple partition USB drive

Not all USB devices are created equal. Most USB Flash sticks report themselves as removable but the USB connected Hard Drives report themselves as FIXED disks, and therefore allow us to create multiple partitions on this type of the USB external drives.

In my blog “WinPE – Dual Boot External USB Drive”, I explored an idea of using WinPE 5.0 and External USB Drive to create a simple solution for capturing and deploying images with ImageX.exe tool. Here, I will use the same idea with one important difference – creation of multiple partitions on a single USB drives that report themselves as FIXED disks. The first partition is formatted as FAT32 with label name “WinPE” and the second one is formatted with NTFS file system, labelled “ImageData”, and available for storing image files larger than 4GB. All bootable files are copied to the “WinPE” partition and therefore visible to all UEFI systems.

How this app – Create UEFI Bootable External USB Drive gets installed

  • You need to have Windows ADK 8.1 installed; download the Windows Assessment and Deployment Kit (Windows ADK) for Windows 8.1 Update here: http://www.microsoft.com/en-us/download/details.aspx?id=39982.
  • Download WinPE-UEFI-BootExternalUSBDrive.zip package from the download section, under Application folder. After you download the file, please do the following:
  1. Unzip the file (for example C:\ WinPE-UEFI-BootExternalUSBDrive).
  2. Connect your external USB Drive to your computer.
  3. Find the Create-UEFIBootabletExternalUSBDrive_x64.exe file (there are two files: one for 32 bit and one for 64 bit architecture, I am using in my example the 64 bit executable).
  4. Ran as administrator the Create-UEFIBootabletExternalUSBDrive_x64.exe tool in order to create Media files that are necessary to make the external USB drive bootable.

Again, this is a two steps process, as shown in the picture below:

UEFI_SelectFolder_01

Picture 01: in the first step you will select the source folder and start creating Bootable Media files

During the first step, please select the folder named WinPE-UEFRI-BootExternalUSBDrive by clicking ‘Browse Source’ button, and once this folder is selected, please click ‘Start’ button to start creation of the Media files (i.e. the files and applications essential for booting USB drive). Please do not close PowerShell Command line windows as shown below.

UEFI_CreatingMedia_02

Picture 02: UEFI bootable Media files being created, do not close command line window

Once all Media files are created, please proceed to the second step in order to make External USB Drive bootable. First click on ‘View Drive(s)’ button to display all available drives. In my example, three drives are detected. Drive # 0 with Windows OS installed and assigned letter ‘C’; drive # 1 is a USB Flash Drive with assigned letter ‘E’ that reports itself as removable, and drive #2 is an external USB drive with letter ‘G’ that reports itself as Fixed. The column named ‘PartitionType’ with its green / red background color will help you select one or more external USB drives form the list, and (for the ‘green’ ones that you want to have partitioned and bootable) click ‘Run’ button. Please note that this process will delete any data previously stored on the selected drive(s).

UEFI_ListDrives_03

Picture 03: Select drive with green background color and Media files are copied to the selected USB drive; in this example drive with Disk Number -2 and Drive Letter – G.

Finally, at the end of the second step, you will have a bootable USB drive. If you explore the contents of the newly created UEFI bootable external USB drive you will see the list of folders as displayed in the picture below.

TwoPartitions_04

Picture 04: List of folders and files on the newly created UEFI external USB drive

 

 

Please do not delete any of the listed folders. The second partition has folder named ‘Images’, and this folder has one subfolder (with name 32-BIT or 64-BIT) which serves as a container for all images files. During the First Step, by clicking a radio button to select 32-BIT or 64-BIT option, you determine the version of bootable files and image tools (like DISM and ImageX.exe command line tools) to be copied to the bootable ‘WinPE’ partition and used in creation of image files, as well as the name of the subfolder inside the ‘Images’ folder on the partition labelled ‘ImageData’. The other folder on the second partition, named ‘Owner Files’ is there to house all the other data files that you want to have stored on the external USB drive.

To see how UEFI Bootable External USB Drive works, please check my blog “WinPE – Dual Boot External USB Drive”, and read the sections under subtitle: ‘How WinPE – Dual Boot External USB Drive works’. The application has the same functions and the same interface (with three tabs: Computer Info, Create Image and Apply Image) as described there.

To download the WinPE – UEFI Bootable External USB Drive application, please go to the site’s download section, and expand the Application folder. In December 2015, I updated the scripts for UEFI devices (low and high resolution). If you want to download the updated scripts , please go to the site’s download section, expand the Application folder and select: WinPE-Sysprep. To get more info about these updated scripts, pleas check this post.


Please note: Although the author has made every reasonable attempt to achieve complete accuracy of the content, he assumes no responsibility for errors or omissions. Also, you should use this information as you see fit, and at your own risk.

 

Edit the Answer File – Unattend.xml

$
0
0

The answer file for Setup, typically called Unattend.xml, is used along with the System Preparation tool (Sysprep) to prepare an installation of Windows operating system for duplication or imaging by capturing a customized Windows master image that we can reuse throughout our organization.

The following is an example of running Syprep with the answer file:

Sysprep /generalize /oobe /shutdown /unattend: Unattend.xml

When you run Sysprep /generalize /oobe command, on the next reboot after you run this command, Windows runs the Specialize configuration pass, Plug and Play, and other Setup tasks before Windows starts OOBE. In order to get past the OOBE screens, an unattend file is used to specify values that apply to the 3, 4 and 7 installation passes, such as the names of user accounts, display settings, how to partition disks, the location of the Windows image to install, and the product key to apply. The Sysprep /unattend option in the above command allows us to use an answer file to automate this process and address Generalize, Specialize and OOBE settings.

The following sections in this blog will demonstrate my way to modify a ‘Generic Answer File’ and change the values such as the Computer Name, User Password, Language settings and Product Key. It should be noted that this can be done for any values in the ‘Generic Answer File’ for as long as there are unique strings to search and replace on.

Generic Answer File

The generic answer file described in this blog has certain characteristics.

Firstly, I am using Imagex.exe tool to apply a captured image and therefore the WinPE pass settings are removed from the sample answer file. In addition, I want to use in my example the AdministratorPassword/AutoLogon feature, and since I am deploying into a workgroup, I have to either specify an extra account in the unattend.xml, or the Windows 7 setup will prompt for a user account creation. Since I have enabled the administrator account and specified that user as an extra account, there is no need for creating an extra user which later may have to be deleted.

Secondly, in the example provided here, my generic answer file has the following unique strings:

  • ‘TEST-123’
  • ‘TEST-ORG’
  • ‘TEST-OWNER’
  • ‘Pacific Standard Time’
  • ‘0409:00000409’
  • ‘en-US’
  • ‘XXXXX-XXXXX-XXXXX-XXXXX-XXXXX’
  • ‘P@ssw0rd’

Form-UnattendFile

Picture 1: Generic answers file with unique strings

How Generic Answer File is used?

1. Reference Computer – run Sysprep

The generic file is used in the process of building a master image on a reference computer.

This building process comprises the following stages:

  • You install Windows OS on a reference computer.
  • After the installation is complete, you boot the computer and install any additional device drivers or applications. Copy the generic answer file into Sysprep directory and name it EditUnattend.xml
  • After you update the Windows installation, you run the Sysprep /generalize /oobe /shutdown /unattend: EditUnattend.xml command. The answer file is validated and then cached to the computer’s %WINDIR%\panther directory where the name of the answer file must be Unattend.xml.
  • After the reference computer shuts down, you can boot to WinPE (in my example: WinPE-DualBootExternalUSBDrive or WinPE-UEFI-BootExternalUSBDrive) to capture the Windows installation with ImageX.exe.

 2. Destination Computer – Edit and Apply Answer File

Boot the destination computer by using your bootable Windows PE media or in my example: WinPE-DualBootExternalUSBDrive or WinPE-UEFI-BootExternalUSBDrive.  If you use my aforementioned WinPE bootable media, you know that default disk formatting option for a destination computer’s hard drive creates two new partitions: the first one with the letter S: for active and hidden System partition and the second one with the letter W: for a partition labelled Windows. This means when you apply the master image, it will be applied to the Windows partition and therefore the location of the Generic Answer File is: W:\Windows\Panther\Unattend.xml.

The form shown in the picture 2 – Edit/Update Unattend File by default looks into the W:\Windows\Panther folder. When you click ‘Read File’ button the form reads the Unattend.xml file and displays all unique strings.

FormEditAnswerFile

 

 

 

 

 

 

 

 

 

 

Picture 2: Edit/Update Unattend File form read the file and displays all unique strings.

The last step as shown in the picture 3 is to change the values in the Unattend .xml file for settings such as the computer name, register organization and owner, product key, etc. To update values in the Unatted.xml file, click the ‘Update File’ button.

CompareTwoForms

Picture 3: change the values in the Unattend .xml file and click ‘Update File’ button.

Note: This is the last step before restarting a destination computer. Once you restart a destination computer the windeploy.exe will finish setup with the changed settings in the Unattend .xml file. This process could be observed if you open and check these log files: setupact.log and setuperr.log, both located in this folder: C:\Windows\Panther\UnattendGC.

WinPE Bootable Media

I have updated my PowerShell scripts in order to include ‘Edit/Update Sysprep Form’ in two WinPE downloads available from my previous posts about USB bootable media:  WinPE – Dual Boot External USB Drive and UEFI Bootable External USB Drive.

The new ‘Apply Image’ portion comprises three tabs as shown in the picture below.

ApplyImage_Partitions

Picture 4: Select MBR or UEFI partition scheme prior to selecting and applying image file.

ApplyImage_SelectOne

Picture 5: Select image file and click on ‘Apply’ button to start the process of applying image on the computer’s hard drive.

Note: selecting desired partition scheme and an installation image as shown in the picture 4 and 5 are mandatory steps.

ApplyImage_Sysprep

Picture 6: Once the image file has been applied to the computer’s hard drive, you can use third tab ‘Sysprep’ to read and update the unattend.xml file.

IMPORTANT: The above Sysprep addition is optional and could be done only in the case that you applied an image previously created with Sysprep /generalize /oobe /shutdown /unattend: EditUnattend.xml command where EditUnattend.xml is a generic answer file. You cannot use this option with a non-sysprepped image or an image that is prepared with a Sysprep command, but the answer file does not have the unique strings to search and replace on.

To download the updated scripts and generic answer file, please go to the site’s download section, expand the Application folder and select: WinPE-Sysprep.

 


 

Use PowerShell to list installed Software from ConfigMgr

$
0
0

In this blog I will share a few PowerShell functions that help me to quickly identify software installed/advertised on a client computer, as well as to list all the computers that have installed a specific application.

This script presents the list of the software installed / advertised on a client computer. Note that you have to provide info for three parameters:

  • SCCM Server name
  • WMI Namespace (the namespace always end with the 3-digit ConfigMgr site code)
  • Name of the client computer (or a file that contains computers’ names)

# PowerShell script: List-SCCMProgramsOnClientComputer.ps1
# Script to list Installed/advertised Software from ConfigMgr
# Author: Alex Dujakovic, Jan 2016
# EXAMPLE: 
# List-SCCMProgramsOnClientComputer.ps1 -SCCMName 'LAB-SCCM-001' 
#      -Namespace 'root\sms\site_ACO' -ClientName 'DART-NS-123'
# List-SCCMProgramsOnClientComputer.ps1 -SCCMName 'LAB-SCCM-001' 
#      -Namespace 'root\sms\site_ACO' -ClientName (Get-Content C:\Test\Pc.txt)
# ============================================================================
[CmdletBinding()]
	Param
        (
            [parameter(Mandatory=$True)]
            [String]
            $SCCMName,            
            
            [parameter(Mandatory=$True)]
            [String]
            $Namespace,
      
            [parameter(Mandatory=$True)]
            [String[]]
            $ClientName
        )
BEGIN{}
PROCESS{
    ForEach ($computer in $ClientName){
        Write-Host $computer -ForegroundColor Green
        If(Test-Connection -ComputerName $computer -Quiet -Count 1){   
            Get-WmiObject -ComputerName "$($SCCMName)" -Namespace "$($Namespace)" `
            -Query ("select InstalledLocation,ProductVersion,ProductName
	        from 
	            SMS_R_System
            join 
                SMS_G_SYSTEM_Installed_Software on SMS_R_System.ResourceID = 
                SMS_G_SYSTEM_Installed_Software.ResourceID
            where
                SMS_R_SYSTEM.Name= ""$($computer)"" ”) |

            Select-Object -Property ProductName, ProductVersion, InstalledLocation | 
            Sort-Object ProductName |       
            Out-GridView -Title $computer
        }
        Else {Write-Host "$computer - Ping Failed" -ForegroundColor Red }
    }
}
END {Write-Host "Done" -ForegroundColor Green}

As a result, this script presents the list of software displayed by Product Name, version and the installation location as shown in the picture below.

SCCMListAdvertisedApps

Picture 01: the GridView displays the name, version and location of installed software.

This function helps me to quickly find all computers that have installed a specific application:


# Author: Alex Dujakovic, Jan 2016
# Function ListComputersInstalledWithSoftware
# ==========================================================================
Function ListComputersInstalledWithSoftware($SCCMName, $Namespace, $SoftwareName){
Get-WmiObject -ComputerName "$($SCCMName)" -Namespace "$($Namespace)" `
-Query ("select 
	SMS_R_SYSTEM.Name
from 
	SMS_R_System 
	inner join SMS_G_System_INSTALLED_SOFTWARE on SMS_G_System_INSTALLED_SOFTWARE.ResourceID = 
    SMS_R_System.ResourceId 
where 
	SMS_G_System_INSTALLED_SOFTWARE.ARPDisplayName like ""$($SoftwareName)%"" ”)| 
    
    Select-Object -Property Name | Sort-Object Name
}
ListComputersInstalledWithSoftware -SCCMName 'LAB-SCCM-001' -Namespace "root\sms\site_ACO" `
                                   -SoftwareName "TextPad"

The following function helps me to find if specific application is installed on a particular computer.


# Author: Alex Dujakovic, Jan 2016
# Function GetInstalledSoftwareInfo
# ==========================================================================
Function GetInstalledSoftwareInfo($SCCMName, $Namespace, $SoftwareName, $ClientName){
$result = (Get-WmiObject -ComputerName "$($SCCMName)" -Namespace "$($Namespace)" `
-Query ("select 
	SMS_R_SYSTEM.Name
from 
	SMS_R_System 
	inner join SMS_G_System_INSTALLED_SOFTWARE on SMS_G_System_INSTALLED_SOFTWARE.ResourceID = 
    SMS_R_System.ResourceId 
where 
    SMS_R_SYSTEM.Name= ""$($ClientName)""
and
	SMS_G_System_INSTALLED_SOFTWARE.ARPDisplayName like ""$($SoftwareName)%"" ”))

 If($result){return "Software: $($SoftwareName) found on computer: $($ClientName)" }
 Else{return "Software: $($SoftwareName) not found on computer: $($ClientName)"}

}
GetInstalledSoftwareInfo -SCCMName 'LAB-SCCM-001' -Namespace "root\sms\site_ACO" `
                         -SoftwareName "TextPad"  -ClientName 'DART-NS-777'

As shown above, rather than using the ConfigMgr reports, you can sometimes use PowerShell scripts to efficiently retrieve information you need. All the scripts could be found in the Download section of this site.



DiskPart GUI – Update

$
0
0

Almost two years ago I wanted to create a DiskPart graphic user interface (GUI) tool for all of my colleagues that do not like command line as much as I do. I used PowerShell to build a DISKPART script to automatically format USB drives as bootable. This script has been posted in a blog with title “DiskPart GUI PowerShell”  and since then it has been downloaded more than 1000 times.

Today, in this blog, I give you an updated script that I hope will be a nice addition to your existing PowerShell scripts and tools, particularly for your Bootable Windows PE USB Drives.

The start page is shown in the picture 1; on the left side you can view the information about detected computer’s drives and on the right side you can select one – and just one – option from a set of partition alternatives.

DiskPartGUI_StartPicture 1: Format Disk Utility start page

To format a drive with selected partition style, please select a drive and then select one partition option as shown in the picture 2. In my example, I selected drive 2 and recommended UEFI\GPT partition to format my external USB drive.

DiskPartGUI_SelectDrivePicture 2: Select disk drive and partition layout MBR or GPT

You have to click on Format Disk button and confirm you choice to start DiskPart and formatting process (as shown in the picture below).

DiskPartGUI_ConfirmSelectionPicture 3: confirm drive selection and partition style

Finally, the second text box becomes visible on the left side and displays the result of all actions produced by DiskPart application.

DiskPartGUI_FormatDrivePicture 4: the second rich text box displays the result of DiskPart actions

This script could be found in the downloaded section – folder Application. Hopefully it will reach thousand downloads just as its predecessor.


 

Update Adobe Flash Player on remote computers

$
0
0

Adobe frequently updates the Flash player in order to remove security flaws and prevent attacks on the computers running this software. As a new version of a software package is released, you might need to update the existing copies of Flash player on your remote machines. These updates can be carried out using a PowerShell script with the Get-WmiObject cmdlet which can be run against remote computers. This means that you can use Windows PowerShell as a management tool.

By default, Get-WmiObject binds to the root\cimv2 namespace on a local computer, making it very easy to return property values for just about any class found in cimv2. Here, two WMI classes will be used:

  • The first one is the Win32_Product WMI class that represents products as they are installed by Windows Installer; in my PowerShell script example, this class uses the Uninstall method with the purpose to uninstall the application/software (i.e. Flash Player) as displayed by win32_product instance.
  • The second one is the Win32_Process WMI class that represents a process on an operating system. The Create method of this class will be used to install Flash player in a form of a Command line to be passed to this method and executed as a new process on remote machine.

Here are the steps in a nutshell:

  • Download the flash player distribution file from the official Adobe site;
  • Create a text file called mms.cfg with purpose to disable auto update of Flash player software;
  • Copy with a script all (distribution and configuration) files to the remote computers;
  • Select the computers that you’d like to deploy software to (in my script example, it is an OU container in Active Directory);
  • Ensure that you have privileged access permissions to the remote computer.

Additional info about disabling auto-update of Adobe Flash player

The following table describes settings in the mms.cfg file:

Parameter Default Description
AutoUpdateDisable 0 0 allows auto-update based on user settings.
1 disables auto-update.
AutoUpdateInterval <0 (or absent)

Takes a numeric value.

<0 (or absent) uses value from player settings.
0 checks for updates every time the player launches.
> 0 specifies the minimum number of days between check for updates.

SilentAutoUpdateEnable 1 1 allows background update.
0 disables background update.

Open Notepad on your computer; create a text file called mms.cfg and type in the following command line:

AutoUpdateDisable=1

Place this file in the same network location with the downloaded flash player distribution file. The PowerShell script will copy mms.cfg file in the following path:  C:\windows\system32\macromed\flash\ on the remote computers.

Once the mms.cfg file is applied, the auto update setting is disabled as shown in the picture below.

FlashPlayerUpdateDisabled

Figure 01: Flash Player is configured to never check for updates.

The PowerShell script example

You have to run this script by ensuring that the administrative access to the remote computers has been set.  It will uninstall Adobe Flash Player 13 ActiveX” and install “Adobe Flash Player 19 ActiveX”.


<# .SYNOPSIS Update-FlashPlayerApp.ps1 Updates Adobe Flash Player software on remote computers. .OUTPUTS One .csv file to record all installed Flash Player software. One .log file to record errors/problems encountered while installing software. .PARAMETER ouName (Mandatory) specifies the computers' container in AD. .PARAMETER logPath (Mandatory) specifies the path to the log file. .EXAMPLE Update-FlashPlayerApp.ps1 -ouName "AFL" Update-FlashPlayerApp.ps1 -ouName "AFL" -WhatIf Update-FlashPlayerApp.ps1 -logPath C:\Log\Update-FlashPlayerLog.log Update-FlashPlayerApp01.ps1 -logPath "C:\Log\FlashProduct.csv" .DESCRIPTION Updates Adobe Flash Player software on remote computers. .NOTES Written by: Alex Dujakovic, Jan 2016 Requires PowerShell Version 3.0 #>
            
[CmdletBinding(SupportsShouldProcess=$True,DefaultParametersetName="UpdateSoftware")]
 
param( 
[Parameter(ParameterSetName="UpdateSoftware", Mandatory=$True, Position=0)] 
[string]$ouName, 

[Parameter(ParameterSetName="ViewLogFile", Mandatory=$True, Position=0)] 
[string]$logPath

)

Import-Module ActiveDirectory

# ---------------------------------------------|LOG FILES|---------------------------
# EDIT THESE LINES ACCORDING TO YOUR ENVIRONMENT

# Log files locations:
$Script:logFile = "C:\PScontainer\Software\Update-FlashPlayerLog.log"
$Script:csvFilePath = "C:\PScontainer\Software\FlashProduct.csv"
# Installation file location:
$Script:installFlashPlayerFile = "\\Server\Share\install_flash_player_19_active_x.msi"

# Check if .CSV file exist, and create empty one with column names
if (!(Test-Path -path $csvFilePath)) { ""|Select Name, Comment | 
Export-Csv -Path $csvFilePath -NoTypeInformation}

# ---------------------------------------------|FUNCTIONS|---------------------------
# UPDATE SOFTWARE FUNCTION

Function Update-Software($ouName){
$findOU = (Get-ADOrganizationalUnit -LDAPFilter "(Name=$ouName)")
$myOU = [ADSI]"LDAP://$($findOU.DistinguishedName)"

$outputArray = New-Object -TypeName System.Collections.ArrayList

$PCcollection = ($myOU.psbase.Children | 
Where  -FilterScript{$_.ObjectCategory -Like "*Computer*"} | 
Select-Object -ExpandProperty Name)
$reachedPCs = (Import-Csv -Path $Script:csvFilePath | 
Select-Object -ExpandProperty Name)

# COPY INSTALLATION FILE FUNCTION

Function CopyAppFile($computer,$path,$destination){
 Write-Host "$($Computer): COPYING INSTALLATION FILES..." -ForegroundColor Green
 if (Test-Path "$($destination)"){
   try {
         $ErrorActionPrefference = "STOP"
         Copy-Item -Path $path -Destination $destination -Force | Out-Null 
         "$($Computer),Copy File From: $path" | 
         Out-file -FilePath $Script:logFile -Encoding ascii -Append
       }

   catch{
         "$($Computer),ERROR Copy-File Error - $($_.Exception.GetType().FullName)`
          - $($_.Exception.Message)" | Out-file -FilePath $logFile -Encoding ascii -Append
        }      
   }

 else{
        
   try{
          $ErrorActionPrefference = "STOP"
          New-Item "$($destination)" -ItemType directory -Force | Out-Null
          "$($Computer),Create Folder: $destination" | 
          Out-file -FilePath $Script:logFile -Encoding ascii -Append
          Copy-Item -Path $path -Destination $destination -Force | Out-Null
          "$($Computer),Copy File From: $path" |
           Out-file -FilePath $Script:logFile -Encoding ascii -Append
       }

   catch{
         "$($Computer),ERROR Create-Folder-Copy File 
         - $($_.Exception.GetType().FullName) - $($_.Exception.Message)" | 
         Out-file -FilePath $Script:logFile -Encoding ascii -Append
       }
   }
}

# UNINSTALL APPLICATION FUNCTION

Function UnInstallApp($computer, $appName){
   Write-Host "$($Computer): UNINSTALLING APPLICATION..." -ForegroundColor Green
    try{
        $ErrorActionPrefference = "STOP"
        $uninstallActiveX = Get-WmiObject -ComputerName $computer`
        -Class 'Win32_Product' -Filter "Name = ""$($appName)"""
        $uninstallActiveX.Uninstall() | Out-Null
         "$($Computer),Application uninstalling ..." | 
         Out-file -FilePath $Script:logFile -Encoding ascii -Append
    }
    catch{
        "$($Computer),ERROR Uninstalling App `
        - $($_.Exception.GetType().FullName - $_.Exception.Message)" | 
        Out-file -FilePath $Script:logFile -Encoding ascii -Append
    }
}

# TERMINATING INTERNET EXPLORER FUNCTION

Function TerminateProcess($computer, $processToTerminate){
Write-Host "$($Computer): TERMINATING IEXPLORE PROCESS..." -ForegroundColor Green
    try{
        $ErrorActionPrefference = "STOP"
        $Processes = (Get-WmiObject -Class Win32_Process -ComputerName $computer)
        foreach($process In $processes){
            if($process.Name -match $processToTerminate){
                $process.Terminate() | Out-Null
            }
        }
         "$($Computer),IE process terminating ..." | 
         Out-file -FilePath $Script:logFile -Encoding ascii -Append
    }
    catch{
        "$($Computer),ERROR Terminating IE 
        - $($_.Exception.GetType().FullName) - $($_.Exception.Message)" | 
        Out-file -FilePath $Script:logFile -Encoding ascii -Append
    }
}

# INSTALL APPLICATION FUNCTION

Function InstallApp($computer,$installString){
Write-Host "$($Computer): SILENTLY INSTALLING APPLICATION..." -ForegroundColor Green
    Try{
        $ErrorActionPrefference = "STOP"
        ([WMICLASS]"\\$computer\ROOT\CIMV2:Win32_Process").Create($InstallString) | 
        Out-Null
        "$($Computer),Aplication installing ..." | 
        Out-file -FilePath $Script:logFile -Encoding ascii -Append
    }
    catch{
        "$($Computer),ERROR Installing App 
        - $($_.Exception.GetType().FullName) - $($_.Exception.Message)" | 
        Out-file -FilePath $Script:logFile -Encoding ascii -Append
    }
}

# CONFIGURE APPLICATION

Function CopyConfigFile($computer,$path,$destination){
   Write-Host "$($Computer): COPYING CONFIGURATION FILES..." -ForegroundColor Green
        try {
               $ErrorActionPrefference = "STOP"
               Copy-Item -Path $path -Destination $destination -Force #| Out-Null
               "$($Computer),Copy Config File From: $path" | 
               Out-file -FilePath $Script:logFile -Encoding ascii -Append
            }

       catch{
             "$($Computer),ERROR Copying Config File - 
             $($_.Exception.GetType().FullName) - $($_.Exception.Message)" | 
             Out-file -FilePath $Script:logFile -Encoding ascii -Append
            }      
}

# FIND OUT AND INSTALL/LOG

Function FlashProduct($computer){
    $FlashProduct = (Get-WmiObject -Class "Win32_Product" -ComputerName $Computer | 
    ? {$_.Name -like "*Adobe*Flash*"})
    # We need info abut  $($FlashProduct.Name) and $($FlashProduct.IdentifyingNumber)
        
switch ("$($FlashProduct.Name)"){
 "Adobe Flash Player 19 ActiveX" {
	  Write-Host "$($computer): FP 19"
	  "$($Computer),Adobe Flash Player 19 Installed " | 
	  Out-file -FilePath $Script:logFile -Encoding ascii -Append
	  $row = ""|Select Name, Comment
	  $row.Name = $Computer.ToString()
	  $row.Comment  = "Adobe Flash Player 19 ActiveX"

	  $outputArray.Add($row)
    break
}
 "Adobe Flash Player 18 ActiveX" {
	  Write-Host "$($computer): FP 18"
	  "$($Computer),Adobe Flash Player 18 Installed " | 
	  Out-file -FilePath $Script:logFile -Encoding ascii -Append
	  $row = ""|Select Name, Comment
	  $row.Name = $Computer.ToString()
	  $row.Comment  = "Adobe Flash Player 18 ActiveX"

	  $outputArray.Add($row)
    break                                        
}
 "Adobe Flash Player 13 ActiveX" {
	  Write-Host "$($computer): Flash Player 13 - reinstalling..."

	  # COPY INSTALLATION FILE FUNCTION
	  CopyAppFile -computer $computer `
	  -path $Script:installFlashPlayerFile -destination "\\$Computer\c$\sw\FlashPlayer19"

	  # UNINSTALL APPLICATION FUNCTION
	  UnInstallApp -computer $computer -appName "Adobe Flash Player 13 ActiveX"

	  # TERMINATING INTERNET EXPLORER FUNCTION
	  TerminateProcess -computer $computer -processToTerminate "iexplore.exe"

	  # INSTALL APPLICATION FUNCTION
	  InstallApp -computer $computer `
	  -installString "msiexec.exe /i \\$Computer\c$\sw\FlashPlayer19\install_flash_player_19_active_x.msi /qn"

	  # CONFIGURE APPLICATION
	  CopyConfigFile -computer $computer `
	  -path "\\W12-gpn-c001\d$\GPOUpdates\Adobe\FlashPlayer19\mms.cfg"`
	  -destination "\\$Computer\c$\Windows\System32\Macromed\Flash"

	  $row = ""|Select Name, Comment
	  $row.Name = $Computer.ToString()
	  $row.Comment  = "Adobe Flash Player 19 ActiveX"

	  $outputArray.Add($row)
    break
	}
 }
}
# -----------------------------------|COMPARE AND LOOP|--------------------------------------------------

$newQueryCollection = (Compare-Object -ReferenceObject $PCcollection -DifferenceObject $reachedPCs |
Where-Object -FilterScript {$_.SideIndicator -eq "<="} |Select-Object -ExpandProperty InputObject | 
Sort InputObject)
 $pcCount = 0
foreach ($Computer In $newQueryCollection){
If (Test-Connection -ComputerName $Computer -ea silentlycontinue -Count 1) {
    "$($Computer),Ping Successful" |Out-file -FilePath $Script:logFile -Encoding ascii -Append 
    Write-Host "$($pcCount). $($Computer) - Ping Successful" -ForegroundColor Green
 try {
     (Get-WmiObject -computerName $Computer Win32_Service `
     -Filter "Name='LanmanServer'" -ErrorAction Stop).StartService() | 
      Out-Null
                
      FlashProduct -computer $computer

    }
 catch{
      "$($Computer),Server Service Error: $($_.Exception.GetType().FullName) 
      - $($_.Exception.Message)" |
      Out-file -FilePath $Script:logFile -Encoding ascii -Append
      Write-Host "$($Computer) - Server Service Error" -ForegroundColor Yellow
    }
 }
else{
     "$($Computer),Ping Failed" | Out-file -FilePath $Script:logFile -Encoding ascii -Append 
     Write-Host "$($pcCount). $($Computer) - Ping Failed" -ForegroundColor Red
    }
 $pcCount ++    
}
$outputArray | Export-Csv -Path $csvFilePath -NoTypeInformation -Append
Write-Host "Script finished execution" -ForegroundColor Red

}

# LOG FUNCTION

Function View-LogFile($logPath){

Import-Csv -Delimiter "," -Path $logPath -Header "Name", "Comment" |
Select -Property Name, Comment | Sort -Property Name, Comment -Unique | 
Out-GridView -Title "Flash Player Update Log"

}

# ---------------------------|END OF FUNCTIONS|-------------------------------------------------------

switch ($PsCmdlet.ParameterSetName) 
    { 
    "UpdateSoftware" {Update-Software $ouName;break} 
    "ViewLogFile"  {View-LogFile $logPath;break} 
}

The output of the Update-FlashPlayerApp.ps1 script is shown in the figure 02.

UpdateFlashPlayerAppFigure 02: Displays the output of Update-FlashPlayerApp.ps1 script

This script could be found in the download section – under PowerShell folder.


 

PowerShell – Export ACLs to Excel File

$
0
0

As an Administrator, you have to monitor how folders are being shared in your domain and manage permissions, making sure that your clients have appropriate access to files and directories. You know very well how Windows NT-based systems allows full control over security and file permissions, but there is no a built-in way to quickly view users’ accesses to a tree of directories on your network shared folder.

Running the Export-ACLToExcelFile.ps1 script

The script presented here provides a snapshot of the users/groups in my domain that have access to the Shared folders and exports ACLs and other info into an Excel Report file.


<# .SYNOPSIS Export-ACLToExcelFile.ps1 collects ACL info and exports result to an Excell File. .OUTPUTS One .xlsx file to record all ACLs on specified folder. .PARAMETER path (Mandatory) specifies the path to the network folder. .PARAMETER permission (Mandatory) specifies the AC Entries to be collected. .EXAMPLE Export-ACLToExcelFile.ps1 -path \\ServerName\PathToFolderName -permission Default Export-ACLToExcelFile.ps1 -path \\ServerName\PathToFolderName -permission Custom .DESCRIPTION Export-ACLToExcelFile.ps1 collects ACL info and exports result to Excell File. .NOTES Written by: Alex Dujakovic, Oct 2016 Requires PowerShell Version 3.0 #>

param( 
[Parameter(Mandatory=$True, Position=0)] 
[string]$path,

[Parameter(Mandatory=$True, Position=1)] 
[string]$permission
) 

As you can see from the portion of the script’s code, it has two mandatory parameters: path and permission and you can run it by typing at the command prompt the following:

Export-ACLToExcelFile.ps1 -path \\ServerName\PathToFolderName -permission Custom

The script outputs an Excel Report file which has two tabs: “ACLs” and “Accounts List”. On the “ACLs” worksheet tab, each row in this report will display the following:  UNC Folder Path, ‘LastWriteTime’ attribute, Owner, Groups and Users, Permissions and the Inheritance property. The picture 1 displays the portion of the Excel Report file for the Z:\Tools folder.

aclexcelreport
Picture 1: display “ACLs” worksheet tab.

In addition to creating a snapshot for the selected folder, I use the Export-ACLToExcelFile.ps1 script as a tool for detecting the security holes and locking down the permissions. Note the two highlighted accounts in the picture 1, with Modify and Full Control access to the Z:\Tools\Transform\Samples folder; in my domain, I want only the security groups to have/control access to the network folders.

On the second tab, named “Accounts List”, there is a sorted list of the security groups and users found in the access control list (ACL).

aclgroupsandusers
Picture 2: displays the list of groups/users accounts that are found in ACLs for the selected folder.

Please note that you do not see entries under Groups/Users as follows:

  • “Everyone”
  • “BUILTIN\Administrators”
  • “NT AUTHORITY\Authenticated Users”
  • “NT AUTHORITY\SYSTEM”
  • “BUILTIN\Users”

The reason for this is the second script’s Parameter/Argument and its value “Custom”. As shown in the code below, I use the switch to list all the entries in ACL (“Default) or filter out entries listed above (“Custom”).

Switch($permission){

"Custom" {
   Switch ("$([string]$aclEntry.IdentityReference)"){
    
     "BUILTIN\Administrators" {}
     "Everyone" {}
     "NT AUTHORITY\Authenticated Users" {}
     "NT AUTHORITY\SYSTEM" {}
     "BUILTIN\Users" {}
     Default { 
      
      $intRow = $intRow + 1 
          
      # Account
      $finalWorkSheet.Cells.Item($intRow,4) = "$([string]$aclEntry.IdentityReference)"
      # Permission 
      $finalWorkSheet.Cells.Item($intRow,5) = "$([string]$aclEntry.FileSystemRights)"
      # Inheritance
      Switch("$([string]$aclEntry.IsInherited)"){
        "TRUE"{$finalWorkSheet.Cells.Item($intRow,6) = "$([string]$aclEntry.IsInherited)"}
        "FALSE"{$finalWorkSheet.Cells.Item($intRow,6).Font.ColorIndex = 3
                $finalWorkSheet.Cells.Item($intRow,6) = "$([string]$aclEntry.IsInherited)"}
      }
     }
   }   
 }

"Default" {
    $intRow = $intRow + 1 

    # Account
    $finalWorkSheet.Cells.Item($intRow, 4) = "$([string]$aclEntry.IdentityReference)"
    # Permission 
    $finalWorkSheet.Cells.Item($intRow, 5) = "$([string]$aclEntry.FileSystemRights)"
    # Inheritance  
       Switch("$([string]$aclEntry.IsInherited)"){
        "TRUE"{$finalWorkSheet.Cells.Item($intRow,6) = "$([string]$aclEntry.IsInherited)"}
        "FALSE"{$finalWorkSheet.Cells.Item($intRow,6).Font.ColorIndex = 3
                $finalWorkSheet.Cells.Item($intRow,6) = "$([string]$aclEntry.IsInherited)"}
       }
     }
    } # End of Switch
   }  # End of foreach ACLs 

Depending on the number of subfolders, this script could run for a very long time and the progress bars are provided for you to follow the progress of a lengthy operation, as shown in the picture 3.

progressbar_acl
Picture 3: showing progress bars for folder ACLs and sorting of ACL entries.
This script could be found in the download section – under PowerShell folder. It provides you with a snapshot of the Shared folders’ permissions, giving you a full view of your file system security settings; in addition, it is a solid tool for detecting security holes and locking down permissions where necessary.




 

PowerShell GUI – Update WPF Form / Controls

$
0
0

Sometimes you need to create simple PowerShell scripts to address a business problem and hand it over to the users’ community where a command line environment is not as welcomed as the point and click environment that many users have become accustomed to.

You have two options to create a GUI for your Powershell script: Windows Forms (WinForms) or Windows Presentation Foundation (WPF).

With different options comes some practical differences, and here I will demonstrate a way to update controls in a WPF/XAML Form.

The simple script here will update textbox and label text while going through for loop.


# Update-FormWPF.ps1
# NOTE:demonstrate updating form built with WPF
# Written by: Alex Dujakovic, Jan 2017

Add-Type -AssemblyName PresentationFramework

# =========|Functions|============================

Function LabelDisplayCounting{
   param( 
   [string]$Text,
   [int]$intNum
)
Switch($intNum){
1 {
    $MsgDisplayCount.Visibility="Visible"
    $MsgDisplayCount.Background="#00FF00"
    $Form.Dispatcher.Invoke([action]{
    $MsgDisplayCount.Content = "$($Text)"},"Render")
   }
5 {
    $MsgDisplayCount.Visibility="Visible"
    $MsgDisplayCount.Background="#FF00FF"
    $Form.Dispatcher.Invoke([action]{
    $MsgDisplayCount.Content = "$($Text)"},"Render")
   }
10 {
    $MsgDisplayCount.Visibility="Visible"
    $MsgDisplayCount.Background="#FFFF00"
    $Form.Dispatcher.Invoke([action]{
    $MsgDisplayCount.Content = "$($Text)"},"Render")
   }
15 {
    $MsgDisplayCount.Visibility="Visible"
    $MsgDisplayCount.Background="#FF0000"
    $Form.Dispatcher.Invoke([action]{
    $MsgDisplayCount.Content = "$($Text)"},"Render")
   }
Default{
    $MsgDisplayCount.Visibility="Visible"
    $Form.Dispatcher.Invoke([action]{
    $MsgDisplayCount.Content = "$($Text)"},"Render")
   }
}  
}

Function TextShowCounting{
   param( [string]$Text )
    $Form.Dispatcher.Invoke([action]{
    $TxtCountOneLine.AddText("$($Text)")},"Render")
}

Function ShowTextMultiLine{
   param(
    [string]$Text,
    [int]$intLine
    )
Switch($intLine){
5 {
    $Form.Dispatcher.Invoke([action]{
    $TxtTextMultiLine.AddText("Number: $($Text) line is blue. `n"); 
    $TxtTextMultiLine.Foreground="Blue"},"Render")
   }
10 {

    $Form.Dispatcher.Invoke([action]{
    $TxtTextMultiLine.AddText("Number: $($Text) line is red. `n"); 
    $TxtTextMultiLine.Foreground="Red" },"Render")
   }
15 {

    $Form.Dispatcher.Invoke([action]{
    $TxtTextMultiLine.AddText("Number: $($Text) line is green. `n"); 
    $TxtTextMultiLine.Foreground="Green"},"Render")
   }
Default{
    $Form.Dispatcher.Invoke([action]{
    $TxtTextMultiLine.AddText("$($Text)`n")},"Render")
   }
 }  
}

Function UpdateThisForm{
 for($i=1;$i-le 15; $i++){
    TextShowCounting -Text "$i "
    LabelDisplayCounting -Text "- $i -" -intNum $i
    ShowTextMultiLine -Text "$i" -intLine $i
    Start-Sleep -Seconds 1
  }
    TextShowCounting -Text "Counting Ended!!!"
    LabelDisplayCounting -Text "The End!!!" -intNum $i
    ShowTextMultiLine -Text "The End!!!"
}

$XAML = @"
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="PowerShell WPF - Updating Form" Height="450" Width="450">
<Grid>
<Label Content="PowerShell WPF - Updating Form" Height="30" HorizontalAlignment="Left" Margin="50,5,0,0" Name="LabelTitle" VerticalAlignment="Top" Width="380" FontSize="18" FontWeight="Bold"/>
<TextBox Height="23" HorizontalAlignment="Left" Margin="30,50,0,0" Name="TxtDisplayCountOneLine" VerticalAlignment="Top" Width="380" />
<Label Content="" Height="25" HorizontalAlignment="Left" HorizontalContentAlignment="Center" Margin="30,80,0,0" Visibility="Hidden" Name="LabelDisplayCount" VerticalAlignment="Top" Width="380" FontWeight="Bold"/>
<TextBox HorizontalAlignment="Left" Margin="30,110,0,0" Name="TxtDisplayTextMultiLine" VerticalAlignment="Top" Width="380" AcceptsReturn="True" TextWrapping="Wrap"/>
<Button Content="COUNT" Height="23" HorizontalAlignment="Left" Margin="300,370,0,0" Name="BtnCount" VerticalAlignment="Top" Width="75" ToolTip="Start counting"/>
<Button Content="CLOSE" Height="23" HorizontalAlignment="Left" Margin="200,370,0,0" Name="BtnClose" VerticalAlignment="Top" Width="75" ToolTip="Close this form"/>
</Grid>
</Window>
"@

#Read XAML
$reader=(New-Object System.Xml.XmlNodeReader $xaml) 
$Form=[Windows.Markup.XamlReader]::Load( $reader )

#Controls
$Count = $Form.FindName('BtnCount')
$Close = $Form.FindName('BtnClose')
$MsgDisplayCount = $Form.FindName('LabelDisplayCount')
$TxtCountOneLine = $Form.FindName('TxtDisplayCountOneLine')
$TxtTextMultiLine = $Form.FindName('TxtDisplayTextMultiLine')

# -------------------|Events|------------------

$Count.Add_Click({
TextShowCounting -Text "Start counting "
LabelDisplayCounting -Text "Start" -intNum 0
ShowTextMultiLine -Text "Start counting "
UpdateThisForm
}) 

$Close.Add_Click({$Form.Close()})

$Form.ShowDialog() | out-null

updatewpf

Picture 1: updating textbox and label controls while going through for loop.

As presented in the code, the WPF form updates its controls in a different way than WinForms.
The source of the problem is that the WPF form is in the same thread as the PowerShell script, and in order to update controls in the form we need to control the thread by calling $Form.Dispatcher.Invoke into [action]… We have to use the overload and specify the DispatcherPriority as “Render” or it won’t update the controls on the WPF form consistently.
The script presented here could be found in the download section – under PowerShell folder.


PowerShell – Export ACLs to Excel File

$
0
0

As an Administrator, you have to monitor how folders are being shared in your domain and manage permissions, making sure that your clients have appropriate access to files and directories. You know very well how Windows NT-based systems allows full control over security and file permissions, but there is no a built-in way to quickly view users’ accesses to a tree of directories on your network shared folder.

Running the Export-ACLToExcelFile.ps1 script

The script presented here provides a snapshot of the users/groups in my domain that have access to the Shared folders and exports ACLs and other info into an Excel Report file.

<# 
.SYNOPSIS Export-ACLToExcelFile.ps1 collects ACL info and exports result to an Excell File. 
.OUTPUTS One .xlsx file to record all ACLs on specified folder. 
.PARAMETER path (Mandatory) specifies the path to the network folder. 
.PARAMETER permission (Mandatory) specifies the AC Entries to be collected. 
.EXAMPLE 
 Export-ACLToExcelFile.ps1 -path \\ServerName\PathToFolderName -permission Default 
 Export-ACLToExcelFile.ps1 -path \\ServerName\PathToFolderName -permission Custom 
.DESCRIPTION Export-ACLToExcelFile.ps1 collects ACL info and exports result to Excell File. 
.NOTES Written by: Alex Dujakovic, Oct 2016 Requires PowerShell Version 3.0 
#>
param( 
[Parameter(Mandatory=$True, Position=0)] 
[string]$path,
[Parameter(Mandatory=$True, Position=1)] 
[string]$permission
) 

As you can see from the portion of the script’s code, it has two mandatory parameters: path and permission and you can run it by typing at the command prompt the following:

Export-ACLToExcelFile.ps1 -path \\ServerName\PathToFolderName -permission Custom

The script outputs an Excel Report file which has two tabs: “ACLs” and “Accounts List”. On the “ACLs” worksheet tab, each row in this report will display the following:  UNC Folder Path, ‘LastWriteTime’ attribute, Owner, Groups and Users, Permissions and the Inheritance property. The picture 1 displays the portion of the Excel Report file for the Z:\Tools folder.

aclexcelreport
Picture 1: display “ACLs” worksheet tab.

In addition to creating a snapshot for the selected folder, I use the Export-ACLToExcelFile.ps1 script as a tool for detecting the security holes and locking down the permissions. Note the two highlighted accounts in the picture 1, with Modify and Full Control access to the Z:\Tools\Transform\Samples folder; in my domain, I want only the security groups to have/control access to the network folders.

On the second tab, named “Accounts List”, there is a sorted list of the security groups and users found in the access control list (ACL).

aclgroupsandusersPicture 2: displays the list of groups/users accounts that are found in ACLs for the selected folder.

Please note that you do not see entries under Groups/Users as follows:

  • “Everyone”
  • “BUILTIN\Administrators”
  • “NT AUTHORITY\Authenticated Users”
  • “NT AUTHORITY\SYSTEM”
  • “BUILTIN\Users”

The reason for this is the second script’s Parameter/Argument and its value “Custom”. As shown in the code below, I use the switch to list all the entries in ACL (“Default) or filter out entries listed above (“Custom”).

Switch($permission){

"Custom" {
   Switch ("$([string]$aclEntry.IdentityReference)"){
    
     "BUILTIN\Administrators" {}
     "Everyone" {}
     "NT AUTHORITY\Authenticated Users" {}
     "NT AUTHORITY\SYSTEM" {}
     "BUILTIN\Users" {}
     Default { 
      
      $intRow = $intRow + 1 
          
      # Account
      $finalWorkSheet.Cells.Item($intRow,4) = "$([string]$aclEntry.IdentityReference)"
      # Permission 
      $finalWorkSheet.Cells.Item($intRow,5) = "$([string]$aclEntry.FileSystemRights)"
      # Inheritance
      Switch("$([string]$aclEntry.IsInherited)"){
        "TRUE"{$finalWorkSheet.Cells.Item($intRow,6) = "$([string]$aclEntry.IsInherited)"}
        "FALSE"{$finalWorkSheet.Cells.Item($intRow,6).Font.ColorIndex = 3
                $finalWorkSheet.Cells.Item($intRow,6) = "$([string]$aclEntry.IsInherited)"}
      }
     }
   }   
 }

"Default" {
    $intRow = $intRow + 1 

    # Account
    $finalWorkSheet.Cells.Item($intRow, 4) = "$([string]$aclEntry.IdentityReference)"
    # Permission 
    $finalWorkSheet.Cells.Item($intRow, 5) = "$([string]$aclEntry.FileSystemRights)"
    # Inheritance  
       Switch("$([string]$aclEntry.IsInherited)"){
        "TRUE"{$finalWorkSheet.Cells.Item($intRow,6) = "$([string]$aclEntry.IsInherited)"}
        "FALSE"{$finalWorkSheet.Cells.Item($intRow,6).Font.ColorIndex = 3
                $finalWorkSheet.Cells.Item($intRow,6) = "$([string]$aclEntry.IsInherited)"}
       }
     }
    } # End of Switch
   }  # End of foreach ACLs 

Depending on the number of subfolders, this script could run for a very long time and the progress bars are provided for you to follow the progress of a lengthy operation, as shown in the picture 3.

progressbar_aclPicture 3: showing progress bars for folder ACLs and sorting of ACL entries.
This script could be found in the download section – under PowerShell folder. It provides you with a snapshot of the Shared folders’ permissions, giving you a full view of your file system security settings; in addition, it is a solid tool for detecting security holes and locking down permissions where necessary.


Wireless Support WinRE 10 – Part One

$
0
0

It seems that many people need to be able to connect to a wireless network via WinPE. In addition, a large percentage of windows systems nowadays don’t have Ethernet port and many businesses are going “wireless only”. If you browse the Internet, you will find several guides/hacks successfully used to build a WinPE with wireless support. In this blog which has two parts, I will describe the way you can use the Windows 10 WinRE.wim image and an optional component (Feature Pack) called WinPE-WiFi-Package to provide support for adding wireless drivers to WinRE, and the ability to create/deploy images over wireless network connections. In the second part I will provide PowerShell script to automate process of creating WinRE with wireless support.

Windows RE (Recovery Environment) and Optional Components

This page provides the Optional Components Reference: https://msdn.microsoft.com/en-us/windows/hardware/commercialize/manufacture/desktop/winpe-add-packages–optional-components-reference

The default Windows RE image contains the following built-in optional components:

•Microsoft-Windows-Foundation-Package
•WinPE-EnhancedStorage
•WinPE-Rejuv
•WinPE-Scripting
•WinPE-SecureStartup
•WinPE-Setup
•WinPE-SRT
•WinPE-WDS-Tools
•WinPE-WMI
•WinPE-StorageWMI-Package (added to the base image in Windows 8.1 and Windows Server 2012 R2)
•WinPE-HTA (added to the base image in Windows 10)

In addition to the list of default ones, here is our hero – WinPE-WiFi-Package

Network/WinPE-WiFi-Package is used by Windows Recovery Environment (Windows RE). This package is included in the base winre.wim file. Note that this package is used by Windows RE only, and you won’t find it in Boot.wim or ADK WinPE.wim, or as an ADK Optional Component.

Windows RE location and Extraction

Windows RE is stored as WinRE.wim file on a device hard drive or SSD in Windows 7, 8/8.1 and 10.  Windows 7 normally saves it on the same partition/volume with Windows, while Windows 8 and 10 usually keep it on the hidden System Reserved partition that also contains boot files and Boot Configuration Data (BCD).

Therefore, the OS Windows 8, Windows 8.1, and Windows 10 will place WinRE.wim in the following locations:
• Single Partition Deployments – WinRE.wim placed on C: drive (Partition 1).
• BIOS with System Partition – WinRE.wim placed on the System Partition (Partition 1).
• UEFI with Recovery Partition – WinRE.wim will be placed on the Recovery Partition (4).
Note that a UEFI system will have an EFI System Partition (1), an MST Partition (2), Windows Partition (3), and Recovery Partition (4).

To get WinRE.wim from a computer installed with Windows OS, look into Windows\System32\Recovery folder, and if you do not see it there (make sure you are viewing Hidden, System OS files) please do the following:
– run command reagentc /info to find out if it is installed and where (and if existent/installed on OS)
– run reagentc /disable to put WinRE.wim back in Windows\System32\Recovery folder so you can copy it, and then run reagentc /enable to put it back.

Picture 01: WinRE.wim file location

To get WinRE.wim from a Microsoft download file, you need to convert an ESD file (the install.esd file is a Windows Electronic Software Download file located in Sources folder) into Install.wim file. The best way to extract WinRE.wim is to create a folder on your C: drive (example C:\ESD) and copy install.esd into this folder. Open Command Prompt as Administrator, get into C:\ESD folder and run the following commands:
– dism /Get-WimInfo /WimFile:install.esd (to get information on the ESD file and find index number that you need; in my example I choose Index 1 because it is a PRO version).

 

 

 

 

 

 

 

 

Picture 02: Using DISM to get info about Install.esd

– dism /export-image /SourceImageFile:install.esd /SourceIndex:1 /DestinationImageFile:install.wim /Compress:max /CheckIntegrity

Picture 03: export/convert ESD file into WIM file

Depending on your computer, the command takes from 10-20 minutes to finish. Mount the Install.wim file and copy WinRE.wim from the Windows\System32\Recovery folder. Regardless of the method used to find Winre.wim, please always make sure to use a version of the file compatible with the version and architecture of Windows for which WinRE is being repaired. For example, if you are repairing WinRE on a Windows 8 64-bit system you should use the Windows 8 64-bit Winre.wim file.

Customizing WinRE and Boot Options Menu

You can customize WinRE.wim by adding packages, languages, drivers, and custom diagnostic or troubleshooting tools. Note that the number of packages, languages, and drivers is limited by the amount of memory available on the PC, and Microsoft, for performance reasons, recommends that you minimize the number of languages, drivers, and tools that you add to the WinRE.wim image.

The customizations steps are as follows:

1. Use DISM to mount WinRE.wim (for example C:\mount).
2. Create the \Sources\Recovery\Tools folder in the WinRE mount folder.
3. Create an .xml file called WinREConfig.xml that describes the custom tool in the boot options menu.
4. Launch Notepad.exe and type the following:

For HTA Custom Tool WinREConfig.xml

For PowerShell Custom Tool WinREConfig.xml


Note the access level as Yes/No value. It specifies whether the imaging tool should be restricted to users with administrative privileges only from the Windows RE tools menu. This setting does not affect the Recovery control panel, which always requires administrative privilege.

5. Save the file using UTF-8 coding. Do not use ANSI. Save this file in \Sources\Recovery\Tools folder.
6. Copy the custom tool in the \Sources\Recovery\Tools folder of the mounted Windows RE image.
You can only add one custom tool to the WinRE boot options menus. This tool must have .EXE extension.

HTA Custom Tool

• mshta.exe
• ACBWinPEx64.hta

Powershell Custom Tool

• powershell.exe
• ACB-WinPEx64.ps1

Picture 04: Custom tool and apps in the Sources\Recovery\Tools folder; note that I’ve used ACBWinPEx64.hta and ACB-WinPEx64.ps1 from my blog WinPE 5.0 GUI (http://www.alexcomputerbubble.com/winpe-5-0-gui/).

If you choose to have PowerShell Tool you need to add WinPE-PowerShell Optional Component.

7. Use DISM to add drivers (wireless drivers and other needed drivers)
8. Use DISM to add apps that you will use in your Recovery Environment
9. Create/export wireless profile to be used in your Recovery Environment

netsh wlan export profile name=”WiFi_SID_Name” folder=D:\ key=clear
(This would result in exporting/creating profile saved in file D:\Wi-Fi-Name.xml where D: is the USB drive)

You could use a PowerShell script instead:


function Export-WlanProfile($ProfileFolder){ 
&lt;# 
.SYNOPSIS 
Exports WLAN profiles 
.EXAMPLE 
Export-WlanProfile -ProfileFolder C:\WinRE-Wireless\WLAN-Profiles 
#&gt; 

 If((Test-Path $ProfileFolder -PathType Container)){
 
 try {
 $wlanProfileCollection = (netsh wlan show profiles) | 
 Select-String -Pattern "All User Profile" | 
 Foreach-Object {$_.ToString()} 
 $wlanProfileCollection | 
 Foreach-Object {$_.Replace(" All User Profile : ",$null)} 
 $wlanProfileCollection | 
 ForEach-Object {netsh wlan export profile $_ $XmlDirectory key=clear} 
 }
 catch{
 Write-Warning "Error exporting WLAN profile(s)!"
 Write-Warning "Error: $($_.Exception.Message)"
 Break
 }
 } 
 Else{
 [System.Windows.Forms.MessageBox]::Show("Folder does not exist!")
 }
} 
Export-WlanProfile -ProfileFolder C:\WinRE-Wireless\WLAN-Profiles

10. Use DISM to commit your customizations steps and unmount the WinRE image
11. Format you USB drive, make it bootable and add customized WinRE image
12. Once you boot your system into WinRE with wireless support you could use PE Network Manager – http://holger.reboot.pro/ to import profile for wireless network or you could type the following command:

net start wlansvc
netsh wlan add profile filename=D:\Wi-Fi-Name.xml

Microsoft, due to security considerations, recommends that that you disable networking when you don’t need connectivity. By default, networking is disabled in WinRE. You can turn on networking when you need it.


 

Wireless Support WinRE 10 – Part Two

$
0
0

In my blog “Wireless Support WinRE 10 – Part One”, I explored an idea of using Windows 10 WinRE.wim image and an optional component (Feature Pack) called WinPE-WiFi-Package to provide support for adding wireless drivers to WinRE. My understanding is that WinRE.wim is just a modified version of a WinPE image, so I can use all the tolls and scripts available for customization of WinPE images.
Here, I will use PowerShell script to automate process of creating WinRE with wireless support.

How this script – Create-BootableWinReUSBDrive.ps1 automate process
1. You need to have Windows Assessment and Deployment Kit (Windows ADK) installed
2. Download WinRE-Wireless.zip package from the download section, under Application folder. After you download the file, please do the following:
3. Unzip the file (in my example C:\ WinRE-Wireless).
4. Connect your external USB Drive to your computer.
5. Find the PowerShell script named: Create-BootableWinReUSBDrive.ps1 (Important: there are two files: Create-BootableWinReUSBDrive.ps1 and WinRE-Build.ps1).
6. Ran as administrator the script named Create-BootableWinReUSBDrive.ps1, which opens a form as an interface to collect all necessary info for the second script named WinRE-Build.ps1 and create Media files that are necessary to make the external USB drive bootable.

Again, this is a two steps process, as described in my previous blogs and shown in the picture below:

Picture 01: in the first step you make your selections and start creating Bootable Media files.
During the first step, please make your selection: select the 32 or 64 Bit Architecture, custom (HTA or PowerShell) tool for WinRE boot option menus, the WinRE.wim file source folder, and the source folder named WinRE-Wireless by clicking ‘Browse Source’ button; once this folder is selected, please click ‘Start’ button to start creation of the Media files (i.e. the files and applications essential for booting USB drive). Important: do not close PowerShell Command line windows as shown below.

Picture 02: WinRE Wireless Media files being created, do not close command line window

Once all Media files are created, please proceed to the second step in order to make External USB Drive bootable. First click on ‘View Drive(s)’ button to display all available drives. Click the radio button to select the file system (FAT 32 or NTFS) to be used to format external USB drive(s). Finally, click ‘Run’ button to format selected USB drive(s) and copy all Media files.
Important: The column named ‘Partition Type’ with its green / red background color will help you distinguished the USB drive that reports itself as Fixed/Removable. The Removable USB drive should not be used with FAT32 option which creates two partitions.

Picture 03: Select a drive, click a radio button and finally click the ‘Run’ button to format the selected drive and copy Media files to the selected USB drive.

Finally, at the end of the second step, you will have a bootable USB drive with WinRE image, wireless support and custom menu option created. If you boot your computer using this USB drive you will see the menu option for Custom Tool (in my example HTA tool) and WinRE detecting Wi-Fi networks.

Picture 04: Custom menu option and Wi-Fi support

To download the WinRE-Wireless application, please go to the site’s download section, and expand the Application folder. In the compressed download file I’ve included a script to export WLAN profile(s).


 


PowerShell – Create USB Recovery Drive

$
0
0

This is the third post in my series about Windows Recovery Environment (Windows RE). Here, I will suggest to you to make a recovery drive and subsequently create a backup ISO image of your bootable USB recovery drive, mainly if you purchase a new computer and it is running smoothly.

The Recovery Drive creates a FAT32 formatted USB that boots in both MBR and UEFI with SecureBoot. It helps you to troubleshoot and fix problems with your PC, even if it won’t start, because the (USB) media contains a bootable copy of Windows RE, and therefore gives you access to all troubleshooting and recovery tools. No product key is required when using the Recovery USB Drive to reinstall Windows 10.

In Windows 10 OS, you can use a command-line tool named RecoverDrive.exe to create a system recovery USB drive. To make a USB recovery drive in Windows 10, please run PowerShell as Admin, and do the following:

  1. Type ‘RecoveryDrive.exe’ on the command line.
  2. In a new window that will appear; please select ‘Back up system files to the recovery drive’.
  3. Select Next.
  4. Choose the USB drive you want to use and click next.
  5. Select Create and let the process complete.
  6. Select Finish

Most guides out there will suggest to you that once you create the USB recovery drive, you will not be able to use it for anything else; that you should remove the USB recovery drive from your computer, label or mark it as such and keep it somewhere safe.

But there is an additional option, described in this post that enables you to use PowerShell script and create a backup ISO image of your bootable USB recovery drive, and whenever you need it again, just restore the backup image to the same or another USB stick.

To use this option, please do not remove (just created) USB recovery drive from your computer as soon as you finished step 6 listed above; close the ‘RecoveryDrive.exe’ window only, and run the following PowerShell script which will produce an ISO File:

Example: CreateOrMount-WinREisoFile.ps1 -Path C:\WinRe\WinRE.iso -Title “WinRE” -Force

The following two pictures display the process of creating a backup ISO image of your bootable USB recovery drive.

Picture 01: closing the RecoverDrive window and changing the current directory to the one containing my PowerShell script.

Picture 02: running a PS script to create a backup ISO image of a USB recovery drive.

Here is the PowerShell script:


<# Name: CreateOrMount-WinREisoFile.ps1 
Author: Alex Dujakovic 
Date: June 2017 
Description: Creates ISO File from USB WinRE Recovery Drive 
Mounts ISO File and creates USB WinRE Drive 
Examples: Mounts ISO File and creates USB WinRE Drive 
CreateOrMount-WinREisoFile.ps1 -ImagePath C:\Test\Win10.iso -USBDriveLetter Z -label 'WinRE' 
Creates ISO File from USB WinRE Recovery Drive 
CreateOrMount-WinREisoFile.ps1 -Path C:\Test\WinRE.iso -Title "WinRE" -Force 
CreateOrMount-WinREisoFile.ps1 -Path C:\Test\WinRE.iso -Force Tested on Windows 10 only 
#> 
            
[CmdletBinding(SupportsShouldProcess=$True,DefaultParametersetName="MountISO")]

param( 
[Parameter(ParameterSetName="MountISO", Mandatory=$True, Position=0)] 
[string]$ImagePath, 

[Parameter(ParameterSetName="MountISO", Position=1)] 
[string]$USBDriveLetter,

[Parameter(ParameterSetName="MountISO", Position=2)] 
[string]$label = "WinRE", 

[Parameter(ParameterSetName="CreateISO", Mandatory=$True, Position=0)] 
[string]$Path,
[Parameter(ParameterSetName="CreateISO", Position=1)] 
[string]$Title = "WinRE", 
[Parameter(ParameterSetName="CreateISO", Position=2)]  
[switch]$Force
)
# -------------------------|Functions|------------------------------------

Function New-IsoFile  
{  
  <# .Synopsis Creates a new .iso file .Description The New-IsoFile cmdlet creates a new .iso file containing content from chosen folders .Example New-IsoFile "c:\tools","c:Downloads\utils" This command creates a .iso file in $env:temp folder (default location) that contains c:\tools and c:\downloads\utils folders. The folders themselves are included at the root of the .iso image. .Example New-IsoFile -FromClipboard -Verbose Before running this command, select and copy (Ctrl-C) files/folders in Explorer first. .Example dir c:\WinPE | New-IsoFile -Path c:\temp\WinPE.iso -BootFile "${env:ProgramFiles(x86)}\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\amd64\Oscdimg\efisys.bin" -Media DVDPLUSR -Title "WinPE" This command creates a bootable .iso file containing the content from c:\WinPE folder, but the folder itself isn't included. Boot file etfsboot.com can be found in Windows ADK. Refer to IMAPI_MEDIA_PHYSICAL_TYPE enumeration for possible media types: http://msdn.microsoft.com/en-us/library/windows/desktop/aa366217(v=vs.85).aspx .Notes NAME: New-IsoFile AUTHOR: Chris Wu LASTEDIT: 03/23/2016 14:46:50 #>  
  
  [CmdletBinding(DefaultParameterSetName='Source')]Param( 
    [parameter(Position=1,Mandatory=$true,ValueFromPipeline=$true, ParameterSetName='Source')]$Source,  
    [parameter(Position=2)][string]$Path = "$env:temp\$((Get-Date).ToString('yyyyMMdd-HHmmss.ffff')).iso",  
    [ValidateScript({Test-Path -LiteralPath $_ -PathType Leaf})][string]$BootFile = $null, 
    [ValidateSet('CDR','CDRW','DVDRAM','DVDPLUSR','DVDPLUSRW','DVDPLUSR_DUALLAYER','DVDDASHR','DVDDASHRW','DVDDASHR_DUALLAYER','DISK','DVDPLUSRW_DUALLAYER','BDR','BDRE')][string] $Media = 'DVDPLUSRW_DUALLAYER', 
    [string]$Title = (Get-Date).ToString("yyyyMMdd-HHmmss.ffff"),  
    [switch]$Force, 
    [parameter(ParameterSetName='Clipboard')][switch]$FromClipboard 
  ) 
 
  Begin {  
    ($cp = new-object System.CodeDom.Compiler.CompilerParameters).CompilerOptions = '/unsafe' 
    if (!('ISOFile' -as [type])) {  
      Add-Type -CompilerParameters $cp -TypeDefinition @' 
public class ISOFile  
{ 
  public unsafe static void Create(string Path, object Stream, int BlockSize, int TotalBlocks)  
  {  
    int bytes = 0;  
    byte[] buf = new byte[BlockSize];  
    var ptr = (System.IntPtr)(&bytes);  
    var o = System.IO.File.OpenWrite(Path);  
    var i = Stream as System.Runtime.InteropServices.ComTypes.IStream;  
  
    if (o != null) { 
      while (TotalBlocks-- > 0) {  
        i.Read(buf, BlockSize, ptr); o.Write(buf, 0, bytes);  
      }  
      o.Flush(); o.Close();  
    } 
  } 
}  
'@  
    } 
  
$i = 0

    if ($BootFile) { 
      if('BDR','BDRE' -contains $Media) { Write-Warning "Bootable image doesn't seem to work with media type $Media" } 
      ($Stream = New-Object -ComObject ADODB.Stream -Property @{Type=1}).Open()  # adFileTypeBinary 
      $Stream.LoadFromFile((Get-Item -LiteralPath $BootFile).Fullname) 
      ($Boot = New-Object -ComObject IMAPI2FS.BootOptions).AssignBootImage($Stream) 
    } 
    $MediaType = @('UNKNOWN','CDROM','CDR','CDRW','DVDROM','DVDRAM','DVDPLUSR','DVDPLUSRW','DVDPLUSR_DUALLAYER','DVDDASHR','DVDDASHRW','DVDDASHR_DUALLAYER','DISK','DVDPLUSRW_DUALLAYER','HDDVDROM','HDDVDR','HDDVDRAM','BDROM','BDR','BDRE') 
    ($Image = New-Object -com IMAPI2FS.MsftFileSystemImage -Property @{VolumeName=$Title}).ChooseImageDefaultsForMediaType($MediaType.IndexOf($Media)) 
  
    if (!($Target = New-Item -Path $Path -ItemType File -Force:$Force -ErrorAction SilentlyContinue)) { Write-Error -Message "Cannot create file $Path. Use -Force parameter to overwrite if the target file already exists."; break } 
  }  
 
  Process { 
    $i++
    $Activity = "Creating ISO File"
    $CurFolderText = '"Item: $($i.ToString().PadLeft($Script:IsoItemsCollection.Count.ToString().Length)) of $($Script:IsoItemsCollection.Count) | $($item.FullName)"'
    $CurFolderBlock = [ScriptBlock]::Create($CurFolderText)
   
    if($FromClipboard) { 
      if($PSVersionTable.PSVersion.Major -lt 5) { Write-Error -Message 'The -FromClipboard parameter is only supported on PowerShell v5 or higher'; break } 
      $Source = Get-Clipboard -Format FileDropList 
    } 

    foreach($item in $Source) { 
    Write-Host " " 
    Write-Host "       Processing:$item"    
      if($item -isnot [System.IO.FileInfo] -and $item -isnot [System.IO.DirectoryInfo]) { 
        $item = Get-Item -LiteralPath $item 
      } 
  if($item){     
  try { 

    $CurFolderpPercent = $i / $Script:IsoItemsCollection.Count * 100
    $Task = "Adding item files into ISO container"
    Write-Progress -Id 1 -Activity $Activity -Status (& $CurFolderBlock) -CurrentOperation $Task -PercentComplete $CurFolderpPercent 

    $Image.Root.AddTree($item. FullName, $true) 
  }
  catch { Write-Error -Message ($_.Exception.Message.Trim() + ' Try a different media type.') } 
  } 
  } 
  } # End of Process
 
  End {  
    if ($Boot) { $Image.BootImageOptions=$Boot }  
    $Result = $Image.CreateResultImage()  
    [ISOFile]::Create($Target.FullName,$Result.ImageStream,$Result.BlockSize,$Result.TotalBlocks) 
    $Target 
    Write-Host "Done! Script is finished executing." -ForegroundColor Green
  } 
}

Function Mount-ISOFile{

    Param(
    [Parameter(Mandatory=$True)]
    [string]$ImagePath,
    [Parameter(Mandatory=$True)]
    [string]$USBDriveLetter,
    [string]$label = "WinRE"
    )

Begin{
    
    Function Get-PBRFile($Drive){
    
    $partitionStyle = (Get-Content -Path "$($Drive)\sources\`$PBR_Diskpart.txt"|
    Select-String -Pattern "convert" |
    ForEach-Object{$_.ToString().Replace("convert " ,$null)})
    return $partitionStyle.Trim()
    }

    Function do_CopyFiles($diskLetter, $folder){

    $FOF_CREATEPROGRESSDLG = "&H0&"
    $objShell = New-Object -ComObject "Shell.Application"
    $objFolder = $objShell.NameSpace($diskLetter)
 
    if(Test-Path -Path $folder){
	$folder = $folder + "\*.*"
        $objFolder.CopyHere($folder, $FOF_CREATEPROGRESSDLG)
    }  
    else{
        [System.Windows.Forms.MessageBox]::Show("Folder does not exist!")
    }
}

# Get USB drive and ISO file size - validate
$Disk = Get-Disk|Where-Object {$_.BusType -eq 'USB'} 
$USBDriveSize = ($Disk | Where-Object Number -eq ($Disk.Number) | Select -ExpandProperty Size)
$ISOFileSize = (Get-ChildItem $ImagePath).Length

If($ISOFileSize -gt $USBDriveSize)
{
Write-Warning "There is not enough free space on USB Drive!!!"
Write-Host "USB Drive capacity: $(($USBDriveSize/1GB).ToString("0.00 GB"))."
Write-Host "ISO File size: $(($ISOFileSize/1GB).ToString("0.00 GB"))."
Write-Warning "A USB drive with a $(($ISOFileSize/1GB).ToString("0.00 GB")) capacity is needed."
Break
}

#Mount ISO File
If(-not(Get-DiskImage -ImagePath $ImagePath | Get-Volume))
    {
        $ISOFileMounted = $true
    Try{  
        Write-Host "Mounting ISO File, please wait ..." -ForegroundColor Green      
        Mount-DiskImage -ImagePath $ImagePath -ErrorAction Stop | Out-Null
    }
    Catch{
        Write-Host "Error: $_.Exception.GetType().FullName; Error: $_.Description" -ForegroundColor Yellow
        Break    
    }
}
Else
   {
     Write-Host "ISO File already mounted" -ForegroundColor Green
}# End of If/Else

$ISODrive = ((Get-DiskImage -ImagePath $ImagePath | Get-Volume).DriveLetter) + ":"

Write-Host "ISO File mounted to $ISODrive" -ForegroundColor Green

$partitionStyle = (Get-PBRFile -Drive $ISODrive)

} # End of Begin
Process{

 $Disk = Get-Disk|Where-Object {$_.BusType -eq 'USB'} 

 Get-Disk -Number ($Disk.Number)| Get-Partition | Remove-Partition -Confirm:$False -ErrorAction SilentlyContinue

 Clear-Disk -Number $Disk.Number -RemoveData -RemoveOEM -Confirm:$false -ErrorAction SilentlyContinue

 Switch($partitionStyle){

    "MBR" {Initialize-Disk -Number $Disk.Number -PartitionStyle MBR -ErrorAction SilentlyContinue}
    "GPT" {Initialize-Disk -Number $Disk.Number -PartitionStyle GPT -ErrorAction SilentlyContinue}

 }
 
 $partition = New-Partition -DiskNumber $Disk.Number -DriveLetter $USBDriveLetter -UseMaximumSize -IsActive

 Format-Volume -Partition $partition -FileSystem FAT32 -NewFileSystemLabel "$($label)"

 Write-Host "USB drive formated, preparing to copy files, please wait ..." -ForegroundColor Green

 $USBDriveLetter = $USBDriveLetter  + ":"

 do_CopyFiles -diskLetter $USBDriveLetter -folder $ISODrive

} # End of Process
End{
     If($ISOFileMounted)
        {
            Write-Host "Dismounting image ..." -ForegroundColor Green
            Dismount-DiskImage -ImagePath $ImagePath
        }
        Write-Host "Recovery USB Drive creation complete!" -ForegroundColor Green
    }
} 
# ---------------------------|End Of Functions|----------------------------------

switch ($PsCmdlet.ParameterSetName){ 
"MountISO"{ 
    Mount-ISOFile -ImagePath $ImagePath -USBDriveLetter $USBDriveLetter -label $label 
 } 
"CreateISO"{
    $Disk= Get-Disk | Where-Object { $_.BusType –eq ‘USB’ }
    $DriveLetter = "$(($Disk | Get-Partition).DriveLetter):\"
    Write-Host "Collecting info about USB Recovery Drive, please wait ..." -ForegroundColor Green
    $Script:IsoItemsCollection = (Get-ChildItem $DriveLetter)
    Write-Host  "Creating ISO File - Adding Folders/Files to ISO File" -ForegroundColor Green
    Dir $DriveLetter | New-IsoFile -Path $Path -Title $Title -Force
 } 
}

And whenever you need USB Recovery drive, just restore the backup image to the same or another USB stick. Run the following PowerShell command:

Example: CreateOrMount-WinREisoFile.ps1 -ImagePath C:\WinRe\WinRE.iso –USBDriveLetter Z -label “WinRE”

Picture 03: recreating USB Recovery drive form an ISO file.

Just as an extra note, the process of making USB recovery drive creates additional files in your computer’s C:\Windows\System32\Recovery folder. These files ($PBR_Diskpart.txt, $PBR_ResetConfig.xml and ReAgent.xml) are present on USB media as well and my Powershell script reads one of them to configure a proper partition style for a bootable USB stick.

Picture 04: additional files created in the computer’s C:\Windows\System32\Recovery folder.

At the end, it is important to remember that a Recovery Drive is BIT specific, and if you create a Recovery Drive in a 64-bit version of Windows 10, you can’t use that drive to boot up and repair a 32-bit version of Windows 10.

The PowerShell script described here is available in download section, under Powershell.

 




Logon Script and PowerShell ADAssist Tool

$
0
0

In one of my first posts, I wrote about a monthly rolling log file which contains information about users’ activity; most importantly when and where each user logs on and logs off his or her computer. In addition, I’ve encouraged you to implement this or similar script in your organization to help you tackle tracking Logon / Logoff activity in your AD environment, which is somewhat a cumbersome process to do without the scripts.

PowerShell ADAssist Tool

Here I will show you an application I use to harness stats data produced by logon/logoff scripts created with PowerShell; my goal was to provide additional tools for smooth and efficient daily administration tasks.

Honestly, almost ten years ago I created an HTA application (see picture 01) with the exact same objective but never finalized the process of rendering all those VB scripts’ functions into PowerShell scripts.

Picture 01: my HTA application created in late 2008.

Instead, in this post I’ve decided to use an idea presented on TechNet script gallery under name “LazyWinAdmin”. The result is “PowerShell ADAssist” as shown in the picture 02.

Picture 02: newly created ADAssist tool

ADAssist is a PowerShell script that generates Windows Forms (WinForms) and provides the following features:

Computer component (as shown in picture 03):

  • Verifies the connectivity and general information for selected computer
  • Provides information regarding computer’s operating system
  • Displays network configuration, update GPOs, list settings and ports
  • Queries and display services, process …

Picture 03: computer section of the ADAssist tool

User component (as shown in picture 04):

  • Displays basic user info
  • Provides list of the computer(s) used by selected user
  • Shows logon activity for selected user and selected log file
  • Launches a tool to display, manage and edit user’s attributes and membership in AD

Picture 04: user section of the ADAssist tool

It is important to note that this tool does not need stats data produced by logon/logoff scripts. You could simply type a computer’s name and click on one of the buttons displayed on the application’s tabs (General, Operating System, Network and Services-Processes). But, the option to harness logon/logoff stats data makes it an efficient Active Directory Management tool, with ability to search and manage your users and computers accounts; it is especially useful in an environment where computers exist with multiple users’ accounts and provides the following:

  • consistent and accurate view of the computers being used by the selected user
  • general information about logon sessions associated with users/computers
  • display status of computers and makes data associated with users’ profiles easily accessible

How you install/configure ADAssist?

No installation required; just download the compressed file from the download/application section of this site and extract it anywhere you want (in my example it is extracted inside C:\PSScript\AD-Assist folder).

Picture 05: Location of ADAssist application

Note the XML file named “ADassistConfigFile.xml” which is an integral part of this app. As shown in picture 06. ADAssist.ps1 script reads XML document and stores the elements’ content into the script’s variables.

Some nodes/elements (like ‘<PcOU>’) could be empty, but some, like user element ‘<UserOU>’ must have value – Distinguished Name of an OU in Active Directory that contains users’ accounts.

Picture 06: ADAssist XML configuration file

If the user element ‘<UserOU>’ in XML file is empty, upon launch of the ADAssist.ps1 script, the select OU windows form will show up to let you choose an organizational unit containing users’ accounts (see the picture 07). The selected OU’s DistinguishedName will be saved in ‘<UserOU>’ element of the ADassistConfigFile.xml file. To complete this step, once you’ve selected an OU, please click ‘OK’ button to close the form, and then on ADAssist form please click ‘Refresh User List’ button to populate drop-down users’ list.

Picture 07: this OU windows form lets you choose an OU containing users’ accounts.

Please click ’Select Log File’ button as shown in picture 08 to finalize configuration settings. In the ‘Select Logon File’ dialog box, either type the path to a file or click ‘Browse’ button to pick a folder holding a file with logon stats data and then by clicking ‘Select’ button, save the selection to the XML configuration file.

Picture 08: Select Logon file

I always use the most recent log file, actually the one being produced by logon script!!! When required to do some auditing related tasks, I use the other log files previously created by logon script.

Certainly, you can always open the ADassistConfigFile.xml file with Notepad and populate its elements with values that correspond to your Active Directory and network environment.

With these configuration settings completed, you enable ADAssist to harness stats data produced by logon/logoff scripts. The script will search the specified Log File for the selected User Name from the drop-down list and produce a list of computers used by a selected user for the period of time encompassed by a logon script.

With ADAssist you can use any log file in your environment, produced by powershell, VB script or a bat file; it is important that the log file has UserName and ComputerName combination.

For example, here is the monthly rolling Log File with name 2012-11.txt as presented in one of my posts; it is not a proper .csv file, but it has separate data fields delimited with a comma, and it does not have a header with a list of column names in the file:

LogDate, LogTime, UserName, ComputerName, Action [NOTE: column names do not exist]

2012-11-12, 11:28 AM, Alex, Halifax-01, Login

2012-11-12, 11:31 AM, Alex, Dartmouth-02, Login

2012-11-12, 11:32 AM, Alex, Halifax-01, Logoff

2012-11-12, 3:30 PM, David, Bedford-03, Logoff

2012-11-12, 3:33 PM, John, Dartmouth-04, Login

Another example could be a Log File named ‘logoninfo.txt’ which is a proper tab separated CSV file and looks as follows:

PCName                      UserName       Date

Bldg05-OC-L0208     Smith.A           2017:04:28:15:28:15

Bldg04-OA-L0081     Parker.F           2017:04:28:15:30:21

Bldg01-03-W0984      Miller.W          2017:04:28:15:30:24

Bldg05-OC-WP160    Trump.D          2017:04:28:15:32:49

To use different Log Files, you need to edit just a few lines of code in ADAssist (lines 230-238 to be specific). In the following paragraphs you can observe how script uses two cmdlets ‘Get-Content’ and ‘Import-CSV’ to  read and parse the above presented text/CSV files.

PowerShell comma delimited log file example (NOTE: this option is integrated in ADAssist):


$obj = New-Object -TypeName PSObject

Get-Content -Path $Script:logFile |

ForEach-Object {

$obj| Add-Member -Force -MemberType Noteproperty -Name "LogDate" -Value $_.Split(",")[0]

$obj| Add-Member -Force -MemberType Noteproperty -Name "LogTime" -Value $_.Split(",")[1]

$obj| Add-Member -Force -MemberType Noteproperty -Name "UserName" -Value $_.Split(",")[2]

$obj| Add-Member -Force -MemberType Noteproperty -Name "PCName" -Value $_.Split(",")[3]

$obj| Add-Member -Force -MemberType Noteproperty -Name "Action" -Value $_.Split(",")[4]

$obj| Where-Object {$_.UserName.Trim() -eq $DropDown.SelectedItem.SamAccountName}

} | Select-Object -Property PCName -Unique | 

VB Script tab separated CSV log file example:


$obj = New-Object -TypeName PSObject

Import-Csv -Delimiter "`t" -Path $Script:logFile -Header "PCName","UserName","Date"| 

Select -Property PCName, UserName, Date |

ForEach-Object {

$obj| Add-Member -Force -MemberType Noteproperty -Name "PCName" -Value $_.PCName

$obj| Add-Member -Force -MemberType Noteproperty -Name "UserName" -Value $_.UserName

$obj| Add-Member -Force -MemberType Noteproperty -Name "Date" -Value $_.Date

$obj| Where-Object {$_.UserName.Trim() -eq $DropDown.SelectedItem.SamAccountName}

} | Select-Object -Property PCName -Unique |

 How ADAssist works?

As previously stated, ADAssist app could be used just by typing a computer name in the ‘Optional – Type Computer Name’ text box and a click on one of the buttons displayed on the tool’s tabs (General, Operating System, Network and Services-Processes). The retrieved information is displayed in the RichTextbox where you have an option to copy it to the clip board or clear the content.

It is important to note that the typed-in computer’s name has precedence over a computer’s name selected in the grid view!

Most likely this tool will be used as shown in the picture 09.

Picture 09: usual ADAssist workflow

First, you will select a user name from drop-down list, then click on the ‘Run-Log File’ button to search the log file and display all computers used by a selected user for the period of time encompassed by logon stats data. If selected user has logged in and out of his/her system, the grid view will display all the computers recorded in the log file, along with their current network status and additional logon session information about other users.

The next step is to select a computer from the grid view and click on one of the buttons laid out on four tabs.

If you have clients located in different OU, but you have the same logon script, you would just click on ‘Select OU’ button and finalize the process of selecting a different OU in your Active Directory. To replace current list of users in the drop-down list with the ones in newly selected OU, please click the ‘Refresh User List’ button.

In addition to the basic information displayed for the selected user account, you could search and obtain user’s logon activity by clicking on ‘User Logon Info’ button – see picture 10. Just type the path to a log file or click ‘Browse’ button to pick a folder holding a file with logon stats data and then click ‘Run’ button to obtain user’s logon activity information.

Picture 10: unfiltered logon activity from one log file

And if you want to view additional user’s attributes or to administer selected user account, you can click on ‘Display User’ button and launch a new Windows form as shown in picture 11.

Picture 11: Administer selected user account

The next post will elaborate more on administration of user accounts in Active Directory as shown in the picture above and the current status of this ‘AD – User Properties’ form is ‘work in progress’. I have more features on the road-map and I would welcome any feature ideas / suggestions.


 

PowerShell ADAssist Tool and List-ADUsers Script

$
0
0

If you would like to read the other parts in this blog series please go to:

Logon Script and PowerShell ADAssist Tool (Part 1)

Different IT environments have IT professionals with different requirements and organizational boundaries, and therefore I’ve received quite a few emails asking the following question:  Is there a way to launch a Windows form to display and edit the selected user account and its attributes in Active Directory without a need to either use an ADAssist tool or the stats produced by logon/logoff scrips?

The short answer is: yes; there is a PowerShell script – List-ADUsers.ps1, see the picture 1. This script you can use to select different users’ OUs in your Active Directory and from drop-down list, select user’s name and click on ‘Display Selected User’ button.

Picture 1: List-ADUsers.ps1

How you install/where you get List-ADUsers.ps1?

No installation required; this PowerShell scrip is just one of the scripts presented with the ADAssist application and it is kept in the same location. I’ve updated the download file just before publishing this post and you can download the compressed file from the download/application section of this site and extract it anywhere you want (in my example it is extracted inside C:\PSScript\AD-Assist folder).

Picture 2: Location of ADAssist application and List-ADUsers.ps1 script

Note the XML file named “ADassistConfigFile.xml” which is an integral part of this application. This file has been updated as well. As shown in picture 03. List-ADUsers.ps1 script reads XML document and stores the elements’ content into the script’s variables.

Some nodes/elements could be empty, but some, like user element ‘<UserOU>’ and ‘<PsFile><UserFile>’ must have value as shown in picture 3.

Picture 3: ADAssist XML configuration file

Start you PowerShell and Run-as admin the List-ADUsers.ps1 script. The button ‘Select OU’ let you choose an organizational unit containing users’ accounts (see the picture 4). The selected OU’s DistinguishedName will be saved in ‘<UserOU>’ element of the ADassistConfigFile.xml file.

Picture 4: selecting users’ OU and saving a selection as default into the ADassistConfigFile.xml file

Important: If you do not select ‘Save as default’ check box, the drop-down list will be loaded with users’ accounts from selected OU container, but the current selection will not be saved into ADassistConfigFile.xml file.  To go back to your default option, just click ‘Refresh/Reset User List’ button.

Finally, to view and display additional user’s attributes or to administer selected user account, you select a user name from the drop-down list and click on ‘Display Selected User’ button. This will launch a new Windows form (Display-ADUserProperties.ps1) as shown in picture 5.

Note: you have an option to display more than one form /user account; just select another user name from the drop-down list and click on ‘Display Selected User’ button.

Picture 5: AD-User Properties form to view and edit user’s account attributes in AD.

The Display-ADUserProperties.ps1 script, shown above in picture 5, is updated and included as well in the download/application section of this site. My intention is to elaborate more on this form and administration of user accounts in my next blog that will be published this month. The final blog in this series about user accounts’ administration will present this Windows Form with two additional tabs: Exchange General and Mailbox Settings as shown in picture 6.

Picture 6: Exchange General and Mailbox Settings tabs

As always, I have more features on the road-map and I would welcome any feature ideas / suggestions.


 

PowerShell AD User Properties Script

$
0
0

If you would like to read the other parts in this blog series please go to:

  1. Logon Script and PowerShell ADAssist Tool (Part 1)
  2. PowerShell ADAssist Tool and List-ADUsers Script (Part 2)

My objective in this post is to present the Display-ADUserProperties.ps1 script that generates Windows Forms (WinForms) and gives you the ability to:

  • Display and edit user’s attributes in AD
  • Change a user’s password setting
  • Unlock / disable / enable a user’s account and manage account’s expiration
  • Delete / move an account and clear selected user’s account attributes
  • View / export / import user’s settings from an XML file
  • Manage a user’s groups’ membership in AD
  • Apply template settings
  • Copy and create new user account in AD

As you know from previously posted blogs (part one or part two in this series), this script is launched by either the AD-Assist.ps1 or List-ADuser.ps1 script. It is placed in the same folder – ADAssist Application (in my example it is extracted inside C:\PSScript\AD-Assist folder), and as the other scripts in this location, it needs the presence of the XML file named “ADassistConfigFile.xml” which is an integral part of this application. See the picture below.

Picture 1: ADassistConfigFile.xml

Let me show you the five tabs of this script: Account, Organization, Membership, Groups and Template. The two remaining tabs: Exchange General and Mailbox Settings will be presented in the next post.

The first tab, ACCOUNT, displays info about the user’s name, profile, password and account expiry settings. All user’s attributes presented in the textboxes are editable and to commit their change (clear, add/edit, remove attributes in their corresponding textboxes) click the ‘Update Account’ button. To change the account expiry and password settings, use the buttons provided on the form.

Picture 1: Account tab shows info about user’s name, profile, password and account expires settings.

The second tab, ORGANIZATION, displays info about the user’s organization, department and account manager. All these attributes presented in the textboxes are editable, and just like on the first tab, to commit their change (clear, add/edit, remove) click the ‘Update Account’ button. To change the account manager settings use the buttons provided on the form.

Picture 2: Organization tab displays info about user’s organization, department and account manager

The third tab, MEMBERSHIP, lists all the (security/distribution) groups the selected user’s account is a member of. To change the account’s membership settings use the buttons provided on the form.

Picture 3: Membership tab lists all the groups the selected user’s account is a member of

The fourth tab, ADD GROUPS, contains controls you can use to select either security or distribution groups in Active Directory and assign membership to the selected user account. The ‘Select Group OU’ button lets you select the OU container that contains the groups to which you want to add a member.

Picture 4: use Add Groups tab to assign membership to the selected user account

The fifth tab, TEMPLATE, enables you to select a user account from a drop-down list and compare its properties with the displayed user’s attributes. In a displayed DataGridView, you can check one; a few or all the template’s attributes and apply it to the selected user’s account. In addition, you can edit the content of the current template’s attribute in a DataGridView text box cell by typing in it and apply its content to the displayed user.

If you exported a user’s attributes to an XML file, or you have created a user’s snapshot file; these files could be imported as a Template and its content compared with the displayed user’s attributes as well. Just click the ‘Copy Properties’ button to apply the template’s properties and commit changes to the selected user account.

Picture 5: use Template tab to select a user account from a drop-down list and compare its properties with the displayed user’s attributes.

The main form contains quite a few buttons, some of them do not need additional explanation (like Enable, Unlock, Move, and Delete button); but some of them, like the ‘Create User Snapshot’ and ‘Copy / Create New User’ buttons, open up the forms enabling you to perform functions such as exporting users’ attributes from the selected OUs or to create a new user account and its mailbox.

For example, to create a user snapshot, click the ‘Browse’ button to select an OU container which contains users’ accounts you want to capture in an XML file. Click the ‘Save As’ button to specify the path for an XML file and lastly click the ‘Export To XML’ button to finalize this process.

Picture 6: Create a user snapshot file

To Copy / Create a new user account, click on the ‘Copy/Create New User’ button; it opens a form that allows you to specify a few essential properties of a new user account, see picture 7.

Picture 7: Copy and create new user account

These following attributes are copied to the newly created account:

Title,ScriptPath,HomeDrive,ProfilePath,HomeDirectory,wWWHomePage,manager,physicalDeliveryOfficeName,telephoneNumber,l,st,postalCode,c,StreetAddress,postOfficeBox,Company,Department,Description,homePhone,pager,facsimileTelephoneNumber,mobile,ipPhone,extensionAttribute1,extensionAttribute2,extensionAttribute3,extensionAttribute4,extensionAttribute5,extensionAttribute6,extensionAttribute7,extensionAttribute8,extensionAttribute9,extensionAttribute10,extensionAttribute11,extensionAttribute12,extensionAttribute13,extensionAttribute14,extensionAttribute15, and memberOf

The function contained in this form will create a mailbox for a new user if you select the specified checkbox and select the mailbox database from the drop-down list.

NOTE: if you do not check the ‘Create new mailbox for this user’ checkbox on the form, only the attributes displayed in the blue font color will be copied to a new user account.

As always, the download file is in the download/application section of this site under name AD Assist Tool.


Exchange – PowerShell AD User Properties Script

$
0
0

If you would like to read the other parts in this blog series please go to:

  1. Logon Script and PowerShell ADAssist Tool (Part 1)
  2. PowerShell ADAssist Tool and List-ADUsers Script (Part 2)
  3. PowerShell AD User Properties Script (Part 3)

This is the final blog in this series about the user accounts’ administration, and here I will present this Windows Form with two additional tabs: Exchange General and Mailbox Settings. This is the updated Display-ADUserProperties.ps1 script.

From the previous blog (part 3) in this series, you’ve learned that this script gives you the ability to:

  • Display and edit a user’s attributes in AD
  • Change a user’s password settings
  • Unlock / disable / enable a user’s account and manage account’s expiration
  • Delete / move an account and clear the selected user’s account attributes
  • View / export / import a user’s settings from an XML file
  • Manage a user’s groups’ membership in AD
  • Apply template settings
  • Copy and create a new user account in AD

In addition to the above list, this script being updated with the Exchange cmdlets enables you to do the following:

  • Create a new user and its mailbox or create a mailbox for the existing user
  • Hide, disable and remove a mailbox
  • Clear, add/edit, remove the custom attributes
  • Manage the mailbox storage limits and item retention settings
  • View / change the delivery options and delivery restrictions

Please note that Display-ADUserProperties.ps1 script is launched by both the AD-Assist.ps1 or List-ADuser.ps1 script, and it is placed in the same folder – ADAssist Application (in my example it is extracted inside C:\PSScript\AD-Assist folder).

If an account you want to administer is not mailbox enabled, you will see the ‘Enable User Mailbox’ button. To enable this account, click the ‘Enable User Mailbox’ button and in the form that pops up, select the checkbox to make the form’s controls enabled. From the drop down list, select the Exchange database and click the ‘Create New User Mailbox’ button as shown in the picture 1.

Picture 1: Enable mailbox for a user account

Note: you will see this button for every user that is mailbox enabled, but hasn’t logged on to mailbox yet, so there is no data to return. After the user logs on, this button will no longer appear.

The Exchange General tab, displays info about the user’s mailbox, such as the number of total items, its size, the database name, and the dates it is being created/modified. All mailbox’s custom attributes presented in the textboxes are editable and to commit their change (clear, add/edit, remove attributes in their corresponding textboxes) click the ‘Update Exchange Info’ button. To hide/unhide the mailbox or to disable/remove it, use the buttons provided on the form.

Picture 2: Exchange General tab shows info about the mailbox’s properties and custom attributes.

The Mailbox Settings tab, displays different settings, like the mailbox storage limits, its items’ retention settings, delivery options and delivery restrictions. All these settings could be changed (clear, add/edit, remove) by the controls and buttons provided on the form.

Picture 3: Mailbox Settings tab

Important: I’ve updated the Display-ADUserProperties.ps1 script and the download file (ADAssist Tool) just before publishing this post and you can download this compressed file from the download/application section of this site.


Viewing all 40 articles
Browse latest View live