diff --git a/windows/win_unzip.ps1 b/windows/win_unzip.ps1 new file mode 100644 index 00000000000..a62f246f5c8 --- /dev/null +++ b/windows/win_unzip.ps1 @@ -0,0 +1,157 @@ +#!powershell +# This file is part of Ansible +# +# Copyright 2015, Phil Schwartz +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +# WANT_JSON +# POWERSHELL_COMMON + +$params = Parse-Args $args; + +$result = New-Object psobject @{ + win_unzip = New-Object psobject + changed = $false +} + +If ($params.creates) { + If (Test-Path $params.creates) { + Exit-Json $result "The 'creates' file or directory already exists." + } + +} + +If ($params.src) { + $src = $params.src.toString() + + If (-Not (Test-Path -path $src)){ + Fail-Json $result "src file: $src does not exist." + } + + $ext = [System.IO.Path]::GetExtension($src) +} +Else { + Fail-Json $result "missing required argument: src" +} + +If (-Not($params.dest -eq $null)) { + $dest = $params.dest.toString() + + If (-Not (Test-Path $dest -PathType Container)){ + Try{ + New-Item -itemtype directory -path $dest + } + Catch { + Fail-Json $result "Error creating $dest directory" + } + } +} +Else { + Fail-Json $result "missing required argument: dest" +} + +If ($params.recurse) { + $recurse = ConvertTo-Bool ($params.recurse) +} +Else { + $recurse = $false +} + +If ($params.rm) { + $rm = ConvertTo-Bool ($params.rm) +} +Else { + $rm = $false +} + +If ($ext -eq ".zip" -And $recurse -eq $false) { + Try { + $shell = New-Object -ComObject Shell.Application + $shell.NameSpace($dest).copyhere(($shell.NameSpace($src)).items(), 20) + $result.changed = $true + } + Catch { + Fail-Json $result "Error unzipping $src to $dest" + } +} +# Requires PSCX +Else { + # Check if PSCX is installed + $list = Get-Module -ListAvailable + + If (-Not ($list -match "PSCX")) { + Fail-Json $result "PowerShellCommunityExtensions PowerShell Module (PSCX) is required for non-'.zip' compressed archive types." + } + Else { + Set-Attr $result.win_unzip "pscx_status" "present" + } + + # Import + Try { + Import-Module PSCX + } + Catch { + Fail-Json $result "Error importing module PSCX" + } + + Try { + If ($recurse) { + Expand-Archive -Path $src -OutputPath $dest -Force + + If ($rm -eq $true) { + Get-ChildItem $dest -recurse | Where {$_.extension -eq ".gz" -Or $_.extension -eq ".zip" -Or $_.extension -eq ".bz2" -Or $_.extension -eq ".tar" -Or $_.extension -eq ".msu"} | % { + Expand-Archive $_.FullName -OutputPath $dest -Force + Remove-Item $_.FullName -Force + } + } + Else { + Get-ChildItem $dest -recurse | Where {$_.extension -eq ".gz" -Or $_.extension -eq ".zip" -Or $_.extension -eq ".bz2" -Or $_.extension -eq ".tar" -Or $_.extension -eq ".msu"} | % { + Expand-Archive $_.FullName -OutputPath $dest -Force + } + } + } + Else { + Expand-Archive -Path $src -OutputPath $dest -Force + } + } + Catch { + If ($recurse) { + Fail-Json $result "Error recursively expanding $src to $dest" + } + Else { + Fail-Json $result "Error expanding $src to $dest" + } + } +} + +If ($rm -eq $true){ + Remove-Item $src -Recurse -Force + Set-Attr $result.win_unzip "rm" "true" +} + +# Fixes a fail error message (when the task actually succeeds) for a "Convert-ToJson: The converted JSON string is in bad format" +# This happens when JSON is parsing a string that ends with a "\", which is possible when specifying a directory to download to. +# This catches that possible error, before assigning the JSON $result +If ($src[$src.length-1] -eq "\") { + $src = $src.Substring(0, $src.length-1) +} +If ($dest[$dest.length-1] -eq "\") { + $dest = $dest.Substring(0, $dest.length-1) +} +Set-Attr $result.win_unzip "src" $src.toString() +Set-Attr $result.win_unzip "dest" $dest.toString() +Set-Attr $result.win_unzip "recurse" $recurse.toString() + +Exit-Json $result; \ No newline at end of file diff --git a/windows/win_unzip.py b/windows/win_unzip.py new file mode 100644 index 00000000000..7c5ac322b97 --- /dev/null +++ b/windows/win_unzip.py @@ -0,0 +1,113 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# (c) 2015, Phil Schwartz +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . + +# this is a windows documentation stub. actual code lives in the .ps1 +# file of the same name + +DOCUMENTATION = ''' +--- +module: win_unzip +version_added: "" +short_description: Unzips compressed files on the Windows node +description: + - Unzips compressed files, and can force reboot (if needed, i.e. such as hotfixes). Has ability to recursively unzip files within the src zip file provided using Read-Archive and piping to Expand-Archive (Using PSCX). If the destination directory does not exist, it will be created before unzipping the file. If a .zip file is specified as src and recurse is true then PSCX will be installed. Specifying rm parameter will allow removal of the src file after extraction. +options: + src: + description: + - File to be unzipped (provide absolute path) + required: true + default: null + aliases: [] + dest: + description: + - Destination of zip file (provide absolute path of directory). If it does not exist, the directory will be created. + required: true + default: null + aliases: [] + rm: + description: + - Remove the zip file, after unzipping + required: no + choices: + - true + - false + - yes + - no + default: false + aliases: [] + recurse: + description: + - Recursively expand zipped files within the src file. + required: no + default: false + choices: + - true + - false + - yes + - no + aliases: [] + creates: + description: + - If this file or directory exists the specified src will not be extracted. + required: no + default: null + aliases: [] +author: Phil Schwartz +''' + +EXAMPLES = ''' +# This unzips a library that was downloaded with win_get_url, and removes the file after extraction +$ ansible -i hosts -m win_unzip -a "src=C:\\LibraryToUnzip.zip dest=C:\\Lib rm=true" all +# Playbook example + +# Simple unzip +--- +- name: Unzip a bz2 (BZip) file + win_unzip: + src: "C:\Users\Phil\Logs.bz2" + dest: "C:\Users\Phil\OldLogs" + creates: "C:\Users\Phil\OldLogs" + +# This playbook example unzips a .zip file and recursively decompresses the contained .gz files and removes all unneeded compressed files after completion. +--- +- name: Unzip ApplicationLogs.zip and decompress all GZipped log files + hosts: all + gather_facts: false + tasks: + - name: Recursively decompress GZ files in ApplicationLogs.zip + win_unzip: + src: C:\Downloads\ApplicationLogs.zip + dest: C:\Application\Logs + recurse: yes + rm: true + +# Install PSCX to use for extracting a gz file + - name: Grab PSCX msi + win_get_url: + url: 'http://download-codeplex.sec.s-msft.com/Download/Release?ProjectName=pscx&DownloadId=923562&FileTime=130585918034470000&Build=20959' + dest: 'C:\\pscx.msi' + - name: Install PSCX + win_msi: + path: 'C:\\pscx.msi' + - name: Unzip gz log + win_unzip: + src: "C:\\Logs\\application-error-logs.gz" + dest: "C:\\ExtractedLogs\\application-error-logs" +'''