c9597e7fac9795a15d02879845e43e6f5d5b2bcd
[libguestfs.git] / tools / virt-win-reg
1 #!/usr/bin/perl -w
2 # virt-win-reg
3 # Copyright (C) 2010 Red Hat Inc.
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19 use warnings;
20 use strict;
21
22 use Sys::Guestfs;
23 use Sys::Guestfs::Lib qw(open_guest);
24 use Win::Hivex;
25 use Win::Hivex::Regedit qw(reg_import reg_export);
26
27 use Pod::Usage;
28 use Getopt::Long;
29 use File::Temp qw/tempdir/;
30 use File::Basename;
31 use Locale::TextDomain 'libguestfs';
32
33 =encoding utf8
34
35 =head1 NAME
36
37 virt-win-reg - Export and merge Windows Registry entries from a Windows guest
38
39 =head1 SYNOPSIS
40
41  virt-win-reg domname 'HKLM\Path\To\Subkey'
42
43  virt-win-reg domname 'HKLM\Path\To\Subkey' name
44
45  virt-win-reg domname 'HKLM\Path\To\Subkey' @
46
47  virt-win-reg --merge domname [input.reg ...]
48
49  virt-win-reg [--options] disk.img ... # instead of domname
50
51 =head1 WARNING
52
53 You must I<not> use C<virt-win-reg> with the I<--merge> option on live
54 virtual machines.  If you do this, you I<will> get irreversible disk
55 corruption in the VM.  C<virt-win-reg> tries to stop you from doing
56 this, but doesn't catch all cases.
57
58 Modifying the Windows Registry is an inherently risky operation.  The format
59 is deliberately obscure and undocumented, and Registry changes
60 can leave the system unbootable.  Therefore when using the I<--merge>
61 option, make sure you have a reliable backup first.
62
63 =head1 DESCRIPTION
64
65 This program can export and merge Windows Registry entries from a
66 Windows guest.
67
68 The first parameter is the libvirt guest name or the raw disk image of
69 a Windows guest.
70
71 If I<--merge> is I<not> specified, then the chosen registry
72 key is displayed/exported (recursively).  For example:
73
74  $ virt-win-reg Windows7 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft'
75
76 You can also display single values from within registry keys,
77 for example:
78
79  $ cvkey='HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion'
80  $ virt-win-reg Windows7 $cvkey ProductName
81  Windows 7 Enterprise
82
83 With I<--merge>, you can merge a textual regedit file into
84 the Windows Registry:
85
86  $ virt-win-reg --merge Windows7 changes.reg
87
88 =head2 NOTE
89
90 This program is only meant for simple access to the registry.  If you
91 want to do complicated things with the registry, we suggest you
92 download the Registry hive files from the guest using L<libguestfs(3)>
93 or L<guestfish(1)> and access them locally, eg. using L<hivex(3)>,
94 L<hivexsh(1)> or L<hivexregedit(1)>.
95
96 =head1 OPTIONS
97
98 =over 4
99
100 =cut
101
102 my $help;
103
104 =item B<--help>
105
106 Display brief help.
107
108 =cut
109
110 my $version;
111
112 =item B<--version>
113
114 Display version number and exit.
115
116 =cut
117
118 my $debug;
119
120 =item B<--debug>
121
122 Enable debugging messages.
123
124 =cut
125
126 my $uri;
127
128 =item B<-c URI>
129
130 =item B<--connect URI>
131
132 If using libvirt, connect to the given I<URI>.  If omitted, then we
133 connect to the default libvirt hypervisor.
134
135 If you specify guest block devices directly, then libvirt is not used
136 at all.
137
138 =cut
139
140 my $format;
141
142 =item B<--format> raw
143
144 Specify the format of disk images given on the command line.  If this
145 is omitted then the format is autodetected from the content of the
146 disk image.
147
148 If disk images are requested from libvirt, then this program asks
149 libvirt for this information.  In this case, the value of the format
150 parameter is ignored.
151
152 If working with untrusted raw-format guest disk images, you should
153 ensure the format is always specified.
154
155 =cut
156
157 my $merge;
158
159 =item B<--merge>
160
161 In merge mode, this merges a textual regedit file into the Windows
162 Registry of the virtual machine.  If this flag is I<not> given then
163 virt-win-reg displays or exports Registry entries instead.
164
165 Note that I<--merge> is I<unsafe> to use on live virtual machines, and
166 will result in disk corruption.  However exporting (without this flag)
167 is always safe.
168
169 =cut
170
171 my $encoding;
172
173 =item B<--encoding> UTF-16LE|ASCII
174
175 When merging (only), you may need to specify the encoding for strings
176 to be used in the hive file.  This is explained in detail in
177 L<Win::Hivex::Regedit(3)/ENCODING STRINGS>.
178
179 The default is to use UTF-16LE, which should work with recent versions
180 of Windows.
181
182 =cut
183
184 my $unsafe_printable_strings;
185
186 =item B<--unsafe-printable-strings>
187
188 When exporting (only), assume strings are UTF-16LE and print them as
189 strings instead of hex sequences.  Remove the final zero codepoint
190 from strings if present.
191
192 This is unsafe and does not preserve the fidelity of strings in the
193 original Registry for various reasons:
194
195 =over 4
196
197 =item *
198
199 Assumes the original encoding is UTF-16LE.  ASCII strings and strings
200 in other encodings will be corrupted by this transformation.
201
202 =item *
203
204 Assumes that everything which has type 1 or 2 is really a string
205 and that everything else is not a string, but the type field in
206 real Registries is not reliable.
207
208 =item *
209
210 Loses information about whether a zero codepoint followed the string
211 in the Registry or not.
212
213 =back
214
215 This all happens because the Registry itself contains no information
216 about how strings are encoded (see
217 L<Win::Hivex::Regedit(3)/ENCODING STRINGS>).
218
219 You should only use this option for quick hacking and debugging of the
220 Registry contents, and I<never> use it if the output is going to be
221 passed into another program or stored in another Registry.
222
223 =back
224
225 =cut
226
227 GetOptions ("help|?" => \$help,
228             "version" => \$version,
229             "connect|c=s" => \$uri,
230             "debug|d" => \$debug,
231             "format=s" => \$format,
232             "merge" => \$merge,
233             "encoding=s" => \$encoding,
234             "unsafe-printable-strings" => \$unsafe_printable_strings,
235     ) or pod2usage (2);
236 pod2usage (1) if $help;
237 if ($version) {
238     my $g = Sys::Guestfs->new ();
239     my %h = $g->version ();
240     print "$h{major}.$h{minor}.$h{release}$h{extra}\n";
241     exit
242 }
243
244 # virt-win-reg only takes a single disk image ...
245 die __"no libvirt domain name or disk image given\n" if @ARGV == 0;
246 my $domname_or_image = shift @ARGV;
247
248 warn "launching libguestfs ..." if $debug;
249
250 my @lib_args = ([$domname_or_image]);
251 push @lib_args, address => $uri if $uri;
252 push @lib_args, rw => 1 if $merge;
253 push @lib_args, format => $format if defined $format;
254 my $g = open_guest (@lib_args);
255 $g->launch ();
256
257 warn "inspecting guest ..." if $debug;
258
259 my @roots = $g->inspect_os ();
260 if (@roots == 0) {
261     die __x("{prog}: No operating system could be detected inside this disk image.\n\nThis may be because the file is not a disk image, or is not a virtual machine\nimage, or because the OS type is not understood by libguestfs.\n\nIf you feel this is an error, please file a bug report including as much\ninformation about the disk image as possible.\n",
262             prog => basename ($0));
263 }
264 if (@roots > 1) {
265     die __x("{prog}: multiboot operating systems are not supported.\n",
266             prog => basename ($0))
267 }
268 my %fses = $g->inspect_get_mountpoints ($roots[0]);
269 my @fses = sort { length $a <=> length $b } keys %fses;
270 my $mountopts = $merge ? "" : "ro";
271 foreach (@fses) {
272     $g->mount_options ($mountopts, $fses{$_}, $_);
273 }
274
275 my $systemroot = $g->inspect_get_windows_systemroot ($roots[0]);
276
277 # Create a working directory to store the downloaded registry files.
278 my $tmpdir = tempdir (CLEANUP => 1);
279
280 # Used when merging (only) to map from the downloaded hiveshortname to
281 # various properties about the hive.  The key is hiveshortname.  The
282 # value is a hashref containing {h} (hive handle) and {hivefile} (full
283 # hive path on the Windows side).
284 my %hives;
285
286 if (!$merge) {                  # Export mode.
287     die __"expecting 1 or 2 more parameters, subkey path and optionally the value to export\n"
288         if @ARGV < 1 || @ARGV > 2;
289
290     my $path = shift @ARGV;
291     my $name = shift @ARGV; # or undef
292
293     # Map this to the hive name.  This function dies on failure.
294     my ($hiveshortname, $hivefile, $prefix);
295     ($hiveshortname, $hivefile, $path, $prefix) = map_path_to_hive ($path);
296
297     # Download the chosen hive.
298     download_hive ($hivefile, $hiveshortname);
299
300     # Open it.
301     my $h = Win::Hivex->open ("$tmpdir/$hiveshortname", debug => $debug);
302
303     unless ($name) {
304         # Export it.
305         warn "exporting $path from $hiveshortname with prefix $prefix ..."
306             if $debug;
307         reg_export ($h, $path, \*STDOUT,
308                     prefix => $prefix,
309                     unsafe_printable_strings => $unsafe_printable_strings);
310     } else {
311         # Export a single key using hivexget.
312         my @args = ("hivexget", "$tmpdir/$hiveshortname", $path, $name);
313         warn "running ", join (" ", @args), " ..." if $debug;
314         system (@args) == 0 or die "hivexget failed: $?"
315     }
316 }
317 else {                          # Import mode.
318     if (@ARGV == 0) {
319         reg_import (\*STDIN, \&import_mapper, encoding => $encoding);
320     } else {
321         foreach (@ARGV) {
322             open my $fh, $_ or die "open: $_: $!";
323             reg_import ($fh, \&import_mapper, encoding => $encoding);
324         }
325     }
326
327     # Now we've done importing, commit all the hive handles and
328     # close them all.
329     foreach (values %hives) {
330         my $h = $_->{h};
331         delete $_->{h};
332         $h->commit (undef);
333     }
334
335     # Upload all the downloaded hives.
336     foreach my $hiveshortname (keys %hives) {
337         upload_hive ($hiveshortname, $hives{$hiveshortname}->{hivefile})
338     }
339
340     # Sync everything.
341     $g->umount_all ();
342     $g->sync ();
343 }
344
345 exit 0;
346
347 # map function passed to reg_import.
348 sub import_mapper
349 {
350     local $_ = shift;
351
352     my ($hiveshortname, $hivefile, $path, $prefix) = map_path_to_hive ($_);
353
354     # Need to download this hive?
355     unless (-f "$tmpdir/$hiveshortname") {
356         download_hive ($hivefile, $hiveshortname);
357
358         my $h = Win::Hivex->open ("$tmpdir/$hiveshortname",
359                                   write => 1, debug => $debug);
360         my %hash = ( h => $h, hivefile => $hivefile );
361         $hives{$hiveshortname} = \%hash;
362     }
363
364     return ($hives{$hiveshortname}->{h}, $path);
365 }
366
367 # Given a path, map that to the name of the hive and the true path
368 # within that hive.
369 sub map_path_to_hive
370 {
371     local $_ = shift;
372     my ($hiveshortname, $hivefile, $path, $prefix);
373
374     if (/^\\?(?:HKEY_LOCAL_MACHINE|HKLM)\\SAM(\\.*)?$/i) {
375         $hiveshortname = "sam";
376         $hivefile = "$systemroot/system32/config/$hiveshortname";
377         $path = defined $1 ? $1 : "\\";
378         $prefix = "HKEY_LOCAL_MACHINE\\SAM";
379     }
380     elsif (/^\\?(?:HKEY_LOCAL_MACHINE|HKLM)\\SECURITY(\\.*)?$/i) {
381         $hiveshortname = "security";
382         $hivefile = "$systemroot/system32/config/$hiveshortname";
383         $path = defined $1 ? $1 : "\\";
384         $prefix = "HKEY_LOCAL_MACHINE\\SECURITY";
385     }
386     elsif (/^\\?(?:HKEY_LOCAL_MACHINE|HKLM)\\SOFTWARE(\\.*)?$/i) {
387         $hiveshortname = "software";
388         $hivefile = "$systemroot/system32/config/$hiveshortname";
389         $path = defined $1 ? $1 : "\\";
390         $prefix = "HKEY_LOCAL_MACHINE\\SOFTWARE";
391     }
392     elsif (/^\\?(?:HKEY_LOCAL_MACHINE|HKLM)\\SYSTEM(\\.*)?$/i) {
393         $hiveshortname = "system";
394         $hivefile = "$systemroot/system32/config/$hiveshortname";
395         $path = defined $1 ? $1 : "\\";
396         $prefix = "HKEY_LOCAL_MACHINE\\SYSTEM";
397     }
398     elsif (/^\\?(?:HKEY_USERS|HKU)\\.DEFAULT(\\.*)?$/i) {
399         $hiveshortname = "default";
400         $hivefile = "$systemroot/system32/config/$hiveshortname";
401         $path = defined $1 ? $1 : "\\";
402         $prefix = "HKEY_LOCAL_MACHINE\\.DEFAULT";
403     }
404     elsif (/^\\?(?:HKEY_USERS|HKU)\\(S-1-5-[-\d]+)(\\.*)?$/i) {
405         my $sid = $1;
406         $hiveshortname = $sid;
407         $prefix = "HKEY_USERS\\$sid";
408         $path = defined $2 ? $2 : "\\";
409         # This requires a recursive call to download the SOFTWARE hive.
410         $hivefile = lookup_pip_of_user_sid ($sid) . "/ntuser.dat";
411     }
412     elsif (/^\\?(?:HKEY_USERS|HKU)\\LocalSystem(\\.*)?$/i) {
413         my $sid = "S-1-5-18";
414         $hiveshortname = $sid;
415         $prefix = "HKEY_USERS\\$sid";
416         $path = defined $1 ? $1 : "\\";
417         # This requires a recursive call to download the SOFTWARE hive.
418         $hivefile = lookup_pip_of_user_sid ($sid) . "/ntuser.dat";
419     }
420     elsif (/^\\?(?:HKEY_USERS|HKU)\\LocalService(\\.*)?$/i) {
421         my $sid = "S-1-5-19";
422         $hiveshortname = $sid;
423         $prefix = "HKEY_USERS\\$sid";
424         $path = defined $1 ? $1 : "\\";
425         # This requires a recursive call to download the SOFTWARE hive.
426         $hivefile = lookup_pip_of_user_sid ($sid) . "/ntuser.dat";
427     }
428     elsif (/^\\?(?:HKEY_USERS|HKU)\\NetworkService(\\.*)?$/i) {
429         my $sid = "S-1-5-20";
430         $hiveshortname = $sid;
431         $prefix = "HKEY_USERS\\$sid";
432         $path = defined $1 ? $1 : "\\";
433         # This requires a recursive call to download the SOFTWARE hive.
434         $hivefile = lookup_pip_of_user_sid ($sid) . "/ntuser.dat";
435     }
436     elsif (/^\\?(?:HKEY_USERS|HKU)\\(.*?)(\\.*)?$/i) {
437         $hiveshortname = "user_$1";
438         $prefix = "HKEY_USERS\\$1";
439         $path = defined $2 ? $2 : "\\";
440         # XXX We should probably look this up properly.
441         if (is_dir_nocase ("/Users/$1")) {
442             $hivefile = "/Users/$1/ntuser.dat"
443         } elsif (is_dir_nocase ("/Documents and Settings/$1")) {
444             $hivefile = "/Documents and Settings/$1/ntuser.dat"
445         } else {
446             die __x("virt-win-reg: {p}: cannot find user directory\n",
447                     p => $1)
448         }
449     }
450     else {
451         die __x("virt-win-reg: {p}: not a supported Windows Registry path\n",
452                 p => $_)
453     }
454
455     return ($hiveshortname, $hivefile, $path, $prefix);
456 }
457
458 # Given a User SID, consult
459 # HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\$sid
460 # and return the ProfileImagePath value.
461 sub lookup_pip_of_user_sid
462 {
463     local $_;
464     my $sid = shift;
465
466     my $path =
467         "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\".
468         $sid;
469
470     my ($hiveshortname, $hivefile, $prefix);
471     ($hiveshortname, $hivefile, $path, $prefix) = map_path_to_hive ($path);
472
473     download_hive ($hivefile, $hiveshortname)
474         unless -f "$tmpdir/$hiveshortname";
475
476     my @args = ("$tmpdir/$hiveshortname", $path, "ProfileImagePath");
477     warn "running hivexget ", join (" ", @args), " ..." if $debug;
478
479     my $fh;
480     open $fh, "-|", "hivexget", @args
481         or die "hivexget: see earlier errors: $!";
482     $_ = <$fh>;
483     close $fh or die "hivexget: see earlier errors: $!";
484
485     chomp;
486
487     # The contents of the registry are a windows path, possibly
488     # containing %systemroot% and %systemdrive% (on Win XP).  Expand
489     # it and remove some other windows-isms.  The caller will do
490     # case_sensitive_path for us, so we don't need to do that.
491     s/%systemroot%/$systemroot/i;
492     s/%systemdrive%//i;
493     s/^c://i;
494     s,\\,/,g;
495
496     $_;
497 }
498
499 sub is_dir_nocase
500 {
501     local $_;
502     my $dir = shift;
503
504     my $windir;
505     eval { $windir = $g->case_sensitive_path ($dir); };
506     if ($@) {
507         return 0;
508     }
509     return $g->is_dir ($windir);
510 }
511
512 # Download a named hive file.  Die on failure.
513 sub download_hive
514 {
515     local $_;
516     my $hivefile = shift;
517     my $hiveshortname = shift;
518
519     my $winfile;
520     eval { $winfile = $g->case_sensitive_path ($hivefile); };
521     if ($@) {
522         die __x("virt-win-reg: {p}: file not found in guest: {err}\n",
523                 p => $hivefile, err => $@);
524     }
525
526     warn "downloading $winfile ..." if $debug;
527     eval { $g->download ($winfile, "$tmpdir/$hiveshortname"); };
528     if ($@) {
529         die __x("virt-win-reg: {p}: could not download registry file: {err}\n",
530                 p => $winfile, err => $@);
531     }
532 }
533
534 # Upload a named hive file.  Die on failure.
535 sub upload_hive
536 {
537     local $_;
538     my $hiveshortname = shift;
539     my $hivefile = shift;
540
541     my $winfile;
542     eval { $winfile = $g->case_sensitive_path ($hivefile); };
543     if ($@) {
544         die __x("virt-win-reg: {p}: file not found in guest: {err}\n",
545                 p => $hivefile, err => $@);
546     }
547
548     warn "uploading $winfile ..." if $debug;
549     eval { $g->upload ("$tmpdir/$hiveshortname", $winfile); };
550     if ($@) {
551         die __x("virt-win-reg: {p}: could not upload registry file: {err}\n",
552                 p => $winfile, err => $@);
553     }
554 }
555
556 =head1 SUPPORTED SYSTEMS
557
558 The program currently supports Windows NT-derived guests starting with
559 Windows XP through to at least Windows 7.
560
561 The following Registry keys are supported:
562
563 =over 4
564
565 =item C<HKEY_LOCAL_MACHINE\SAM>
566
567 =item C<HKEY_LOCAL_MACHINE\SECURITY>
568
569 =item C<HKEY_LOCAL_MACHINE\SOFTWARE>
570
571 =item C<HKEY_LOCAL_MACHINE\SYSTEM>
572
573 =item C<HKEY_USERS\.DEFAULT>
574
575 =item C<HKEY_USERS\I<SID>>
576
577 where I<SID> is a Windows User SID (eg. C<S-1-5-18>).
578
579 =item C<HKEY_USERS\I<username>>
580
581 where I<username> is a local user name (this is a libguestfs extension).
582
583 =back
584
585 You can use C<HKLM> as a shorthand for C<HKEY_LOCAL_MACHINE>, and
586 C<HKU> for C<HKEY_USERS>.
587
588 The literal keys C<HKEY_USERS\$SID> and C<HKEY_CURRENT_USER> are not
589 supported (there is no "current user").
590
591 =head1 ENCODING
592
593 C<virt-win-reg> expects that regedit files have already been reencoded
594 in the local encoding.  Usually on Linux hosts, this means UTF-8 with
595 Unix-style line endings.  Since Windows regedit files are often in
596 UTF-16LE with Windows-style line endings, you may need to reencode the
597 whole file before or after processing.
598
599 To reencode a file from Windows format to Linux (before processing it
600 with the I<--merge> option), you would do something like this:
601
602  iconv -f utf-16le -t utf-8 < win.reg | dos2unix > linux.reg
603
604 To go in the opposite direction, after exporting and before sending
605 the file to a Windows user, do something like this:
606
607  unix2dos linux.reg | iconv -f utf-8 -t utf-16le > win.reg
608
609 For more information about encoding, see L<Win::Hivex::Regedit(3)>.
610
611 If you are unsure about the current encoding, use the L<file(1)>
612 command.  Recent versions of Windows regedit.exe produce a UTF-16LE
613 file with Windows-style (CRLF) line endings, like this:
614
615  $ file software.reg
616  software.reg: Little-endian UTF-16 Unicode text, with very long lines,
617  with CRLF line terminators
618
619 This file would need conversion before you could I<--merge> it.
620
621 =head1 CurrentControlSet etc.
622
623 Registry keys like C<CurrentControlSet> don't really exist in the
624 Windows Registry at the level of the hive file, and therefore you
625 cannot modify these.
626
627 C<CurrentControlSet> is usually an alias for C<ControlSet001>.  In
628 some circumstances it might refer to another control set.  The way
629 to find out is to look at the C<HKLM\SYSTEM\Select> key:
630
631  # virt-win-reg WindowsGuest 'HKLM\SYSTEM\Select'
632  [HKEY_LOCAL_MACHINE\SYSTEM\Select]
633  "Current"=dword:00000001
634  "Default"=dword:00000001
635  "Failed"=dword:00000000
636  "LastKnownGood"=dword:00000002
637
638 "Current" is the one which Windows will choose when it boots.
639
640 Similarly, other C<Current...> keys in the path may need to
641 be replaced.
642
643 =head1 WINDOWS TIPS
644
645 Note that some of these tips modify the guest disk image.  The guest
646 I<must> be shut off, else you will get disk corruption.
647
648 =head2 RUNNING A BATCH SCRIPT WHEN A USER LOGS IN
649
650 Prepare a DOS batch script, VBScript or executable.  Upload this using
651 L<guestfish(1)>.  For this example the script is called C<test.bat>
652 and it is uploaded into C<C:\>:
653
654  guestfish -i -d WindowsGuest upload test.bat /test.bat
655
656 Prepare a regedit file containing the registry change:
657
658  cat > test.reg <<'EOF'
659  [HKLM\Software\Microsoft\Windows\CurrentVersion\RunOnce]
660  "Test"="c:\\test.bat"
661  EOF
662
663 In this example we use the key C<RunOnce> which means that the script
664 will run precisely once when the first user logs in.  If you want it
665 to run every time a user logs in, replace C<RunOnce> with C<Run>.
666
667 Now update the registry:
668
669  virt-win-reg --merge WindowsGuest test.reg
670
671 =head2 INSTALLING A SERVICE
672
673 This section assumes you are familiar with Windows services, and you
674 either have a program which handles the Windows Service Control
675 Protocol directly or you want to run any program using a service
676 wrapper like SrvAny or the free RHSrvAny.
677
678 First upload the program and optionally the service wrapper.  In this
679 case the test program is called C<test.exe> and we are using the
680 RHSrvAny wrapper:
681
682  guestfish -i -d WindowsGuest <<EOF
683    upload rhsrvany.exe /rhsrvany.exe
684    upload test.exe /test.exe
685  EOF
686
687 Prepare a regedit file containing the registry changes.  In this
688 example, the first registry change is needed for the service itself or
689 the service wrapper (if used).  The second registry change is only
690 needed because I am using the RHSrvAny service wrapper.
691
692  cat > service.reg <<'EOF'
693  [HKLM\SYSTEM\ControlSet001\services\RHSrvAny]
694  "Type"=dword:00000010
695  "Start"=dword:00000002
696  "ErrorControl"=dword:00000001
697  "ImagePath"="c:\\rhsrvany.exe"
698  "DisplayName"="RHSrvAny"
699  "ObjectName"="NetworkService"
700  
701  [HKLM\SYSTEM\ControlSet001\services\RHSrvAny\Parameters]
702  "CommandLine"="c:\\test.exe"
703  "PWD"="c:\\Temp"
704  EOF
705
706 Notes:
707
708 =over 4
709
710 =item *
711
712 For use of C<ControlSet001> see the section above in this manual page.
713 You may need to adjust this according to the control set that is in
714 use by the guest.
715
716 =item *
717
718 C<"ObjectName"> controls the privileges that the service will have.
719 An alternative is C<"ObjectName"="LocalSystem"> which would be the
720 most privileged account.
721
722 =item *
723
724 For the meaning of the magic numbers, see this Microsoft KB article:
725 L<http://support.microsoft.com/kb/103000>.
726
727 =back
728
729 Update the registry:
730
731  virt-win-reg --merge WindowsGuest service.reg
732
733 =head1 SHELL QUOTING
734
735 Be careful when passing parameters containing C<\> (backslash) in the
736 shell.  Usually you will have to use 'single quotes' or double
737 backslashes (but not both) to protect them from the shell.
738
739 Paths and value names are case-insensitive.
740
741 Libvirt guest names can contain arbitrary characters, some of which
742 have meaning to the shell such as C<#> and space.  You may need to
743 quote or escape these characters on the command line.  See the shell
744 manual page L<sh(1)> for details.
745
746 =head1 SEE ALSO
747
748 L<hivex(3)>,
749 L<hivexsh(1)>,
750 L<hivexregedit(1)>,
751 L<guestfs(3)>,
752 L<guestfish(1)>,
753 L<virt-cat(1)>,
754 L<Sys::Guestfs(3)>,
755 L<Sys::Guestfs::Lib(3)>,
756 L<Win::Hivex(3)>,
757 L<Win::Hivex::Regedit(3)>,
758 L<Sys::Virt(3)>,
759 L<http://libguestfs.org/>.
760
761 =head1 BUGS
762
763 When reporting bugs, please enable debugging and capture the
764 I<complete> output:
765
766  export LIBGUESTFS_DEBUG=1
767  virt-win-reg --debug [... rest ...] > /tmp/virt-win-reg.log 2>&1
768
769 Attach /tmp/virt-win-reg.log to a new bug report at
770 L<https://bugzilla.redhat.com/>
771
772 =head1 AUTHOR
773
774 Richard W.M. Jones L<http://people.redhat.com/~rjones/>
775
776 =head1 COPYRIGHT
777
778 Copyright (C) 2010 Red Hat Inc.
779
780 This program is free software; you can redistribute it and/or modify
781 it under the terms of the GNU General Public License as published by
782 the Free Software Foundation; either version 2 of the License, or
783 (at your option) any later version.
784
785 This program is distributed in the hope that it will be useful,
786 but WITHOUT ANY WARRANTY; without even the implied warranty of
787 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
788 GNU General Public License for more details.
789
790 You should have received a copy of the GNU General Public License
791 along with this program; if not, write to the Free Software
792 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.